/**
* @file This file handles the display of subtitles for a video player. It takes no direct input, but it relies on the presence of specific HTML elements on the page, such as a container for the subtitles and a video element.
The purpose of this code is to extract the start and end times of each subtitle from the text content of HTML paragraph elements (< p >), and then display the corresponding subtitle text in the subtitle container when the video playback time falls within the start and end times of that subtitle.
* @author Kor Dwarshuis
* @version 1.0.0
* @since 2023-02-12
*/
const handleSubtitles = () => {
let counter = document.querySelector('.counter');
let subtitlecontainer = document.querySelector('.subtitlecontainer');
const convert = (timestamp) => {
//https://stackoverflow.com/a/9640384 modified. Minutes are worth 60 seconds. Hours are worth 60 minutes:
return +timestamp[0] * 60 * 60 + +timestamp[1] * 60 + +timestamp[2][0];
};
if (subtitlecontainer !== null) {
const paragraphs = document.querySelectorAll('p');
let paragraphIndex = [];
paragraphs.forEach((p) => {
const matchStartTime = p.innerText.match(/[0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]/);
const matchEndTime = p.innerText.match(/,[0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]/);
if (matchStartTime && matchEndTime) {
const strStartTime = matchStartTime[0];
const strEndTime = matchEndTime[0].slice(1); // slice the separator, a comma
// start time
let arrStartTime = strStartTime.split(':'); // split it at the colons
arrStartTime[2] = arrStartTime[2].split('.'); // split at the dot
// leave the miliseconds after the dot
let secondsStartTime = convert(arrStartTime);
// and place them back after the seconds are dealt with
secondsStartTime = secondsStartTime + '.' + arrStartTime[2][1];
// end time
let arrEndTime = strEndTime.split(':'); // split it at the colons
arrEndTime[2] = arrEndTime[2].split('.');
// leave the miliseconds after the dot
let secondsEndTime = convert(arrEndTime);
// and place them back after the seconds are dealt with
secondsEndTime = secondsEndTime + '.' + arrEndTime[2][1];
paragraphIndex.push({
text: p.innerHTML.slice(24), // remove the timestamps and the trailing space
start: secondsStartTime,
end: secondsEndTime,
});
} else {
console.error('No match found in paragraph text');
}
});
document.querySelector('video').addEventListener('timeupdate', (event) => {
counter.innerText = event.target.currentTime;
paragraphIndex.forEach((p) => {
event.target.currentTime > p.start &&
event.target.currentTime < p.end &&
subtitlecontainer.innerHTML !== p.text
? (subtitlecontainer.innerHTML = p.text)
: null;
});
});
}
};
export function onRouteDidUpdate({ location, previousLocation }) {
// Don't execute if we are still on the same page; the lifecycle may be fired
// because the hash changes (e.g. when navigating between headings)
if (location.pathname === previousLocation?.pathname) return;
handleSubtitles();
}