(function(){
var players = document.querySelectorAll('[data-audio-captions][data-captions-url]');
var parseTimestamp = function(value) {
var parts = value.trim().split(':');
var seconds = parts.pop() || '0';
var minutes = parts.pop() || '0';
var hours = parts.pop() || '0';
return (Number(hours) * 3600) + (Number(minutes) * 60) + Number(seconds.replace(',', '.'));
};
var parseCues = function(text) {
return text
.replace(/\r/g, '')
.split(/\n\n+/)
.map(function(block) { return block.split('\n').filter(Boolean); })
.filter(function(lines) { return lines.length >= 2 && lines[0] !== 'WEBVTT'; })
.map(function(lines) {
if (!lines[0].includes('-->')) {
lines.shift();
}
var timing = lines.shift() || '';
var parts = timing.split('-->').map(function(part) { return part.trim(); });
return {
start: parseTimestamp(parts[0] || '0'),
end: parseTimestamp(parts[1] || '0'),
text: lines.join(' '),
};
})
.filter(function(cue) { return Number.isFinite(cue.start) && Number.isFinite(cue.end) && cue.text !== ''; });
};
var findCue = function(cues, time) {
return cues.find(function(cue) { return time >= cue.start && time < cue.end; })
|| cues.find(function(cue) { return time < cue.start; })
|| cues[cues.length - 1]
|| null;
};
players.forEach(function(player) {
var audio = player.querySelector('audio');
var output = player.querySelector('[data-audio-captions-output]');
if (!audio || !output) {
return;
}
fetch(player.dataset.captionsUrl)
.then(function(response) { return response.ok ? response.text() : ''; })
.then(function(text) {
var cues = parseCues(text);
var activeText = '';
var render = function() {
var cue = findCue(cues, audio.currentTime);
if (!cue || cue.text === activeText) {
return;
}
activeText = cue.text;
output.textContent = cue.text;
};
render();
audio.addEventListener('timeupdate', render);
audio.addEventListener('seeked', render);
audio.addEventListener('play', render);
});
});
})();
We use essential cookies to run the site. With your permission, we also use analytics and personalized advertising. Advertising consent allows us to share hashed contact details and location details with Google to match trial and lifetime conversions. Read our
Privacy Policy.