Each track has a mode property (and a mode attribute) that can be: "disabled", "hidden" or "showing". More than one track at a time can be in any of these states. The difference between "hidden" and "disabled" is that hidden tracks can fire events (more on that at the end of the first example) whereas disabled tracks do not fire events.
The CodePen below shows the use of the mode property, and how to listen for cue events in order to capture the current subtitle/caption from JavaScript. You can change the mode of each track in the video element by clicking on its button. This will toggle the mode of that track. All tracks with mode="showing" or mode="hidden" will have the content of their cues displayed in real time in a small area below the video:
HTML code:
<html lang="en">
<head>
<title>Example of track modes</title>
</head>
<body onload="init();">
<p style="text-align: left;">This setup contains a video encoded in both <a href="http://demo.jwplayer.com/html5-report/sintel.webm">WebM</a> and <a href="http://demo.jwplayer.com/html5-report/sintel.mp4">MP4</a>. The video contains four tracks:</p>
<p>
<video id="myVideo" preload="metadata" poster ="http://mainline.i3s.unice.fr/mooc/sintel.jpg" crossorigin="anonymous" controls="controls" width="640" height="272">
<source src="https://mainline.i3s.unice.fr/mooc/sintel.mp4" type="video/mp4" />
<source src="https://mainline.i3s.unice.fr/mooc/sintel.webm" type="video/webm" />
<track src="https://mainline.i3s.unice.fr/mooc/sintel-captions.vtt" kind="captions" label="English Captions" default/>
<track src="https://mainline.i3s.unice.fr/mooc/sintel-descriptions.vtt" kind="descriptions" label="Audio Descriptions" />
<track src="https://mainline.i3s.unice.fr/mooc/sintel-chapters.vtt" kind="chapters" label="Chapter Markers" />
<track src="https://mainline.i3s.unice.fr/mooc/sintel-thumbs.vtt" kind="metadata" label="Preview Thumbs" /></video></p>
<div id="currentTrackStatuses"></div><p>
<div id="subtitlesCaptions"></div><p>
<button onclick="clearSubtitlesCaptions();">Clear subtitles/captions log</button></p>
<p>Click one of these buttons to toggle the mode of each track:</p>
<button onclick="toggleTrack(0);">Toggle english caption track mode</button><br>
<button onclick="toggleTrack(1);">Toggle audio description track mode</button><br>
<button onclick="toggleTrack(2);">Toggle chapter track mode</button><br>
<button onclick="toggleTrack(3);">Toggle preview thumbnail track modes</button>
</body>
</html>
CSS code:
#subtitlesCaptions, #currentTrackStatuses {
padding: 9.5px;
margin: 0 0 10px;
font-size: 13px;
line-height: 1.42857143;
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
height:110px;
overflow:auto;
}
JS code:
let tracks, video, statusDiv, subtitlesCaptionsDiv;
function init() {
video = document.querySelector("#myVideo");
statusDiv = document.querySelector("#currentTrackStatuses");
subtitlesCaptionsDiv = document.querySelector("#subtitlesCaptions");
//tracks = video.textTracks;
tracks = document.querySelectorAll("track");
video.addEventListener('loadedmetadata', () => {
console.log("metadata loaded");
// define cue listeners for the tracks
for(let i=0; i<tracks.length; i++) {
let t = tracks[i].track;
if(t.mode === "showing") {
t.addEventListener('cuechange', logCue, false);
}
}
// fill the log
displayTrackStatus();
});
}
function displayTrackStatus() {
for(let i=0; i<tracks.length; i++) {
var t = tracks[i].track;
let mode = t.mode;
if(mode === "disabled") {
mode = "<span style='color:red'>" + t.mode + "</span>";
} else if(mode === "showing") {
mode = "<span style='color:green'>" + t.mode + "</span>";
}
appendToScrollableDiv(statusDiv, "track "+i+": " + t.label + " "+t.kind+" in "+mode+" mode");
}
}
function appendToScrollableDiv(div, text) {
let inner = div.innerHTML;
div.innerHTML = inner + text + "<br/>";
div.scrollTop = div.scrollHeight;
}
function clearDiv(div) {
div.innerHTML = '';
}
function clearSubtitlesCaptions() {
clearDiv(subtitlesCaptionsDiv);
}
function toggleTrack(i) {
let t = tracks[i].track;
switch (t.mode) {
case "disabled":
t.addEventListener('cuechange', logCue, false);
t.mode = "hidden";
break;
case "hidden":
t.mode = "showing";
break;
case "showing":
t.removeEventListener('cuechange', logCue, false);
t.mode = "disabled";
break;
}
clearDiv(statusDiv);
displayTrackStatus();
appendToScrollableDiv(statusDiv,"<br>" + t.label+" are now " +t.mode);
}
function logCue() {
console.log("log cues");
if(this.activeCues && this.activeCues.length) {
let t = this.activeCues[0].text;
appendToScrollableDiv(subtitlesCaptionsDiv, "Active "+this.kind+" changed to: "+t);
}
}