59 lines
1.5 KiB
JavaScript
59 lines
1.5 KiB
JavaScript
|
|
// subtitles.js
|
||
|
|
|
||
|
|
let _hideTimeout = null;
|
||
|
|
let _revealTimeouts = [];
|
||
|
|
let _enabled = true;
|
||
|
|
|
||
|
|
export function setSubtitlesEnabled(enabled) {
|
||
|
|
_enabled = enabled;
|
||
|
|
if (!enabled) {
|
||
|
|
const container = document.getElementById('subtitle-container');
|
||
|
|
if (container) container.classList.remove('visible');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getSubtitlesEnabled() {
|
||
|
|
return _enabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function showSubtitleStreaming(text, totalDurationSeconds, mode = "word") {
|
||
|
|
if (!_enabled) return;
|
||
|
|
|
||
|
|
const container = document.getElementById('subtitle-container');
|
||
|
|
|
||
|
|
// Clear any pending timeouts from the previous chunk
|
||
|
|
if (_hideTimeout !== null) {
|
||
|
|
clearTimeout(_hideTimeout);
|
||
|
|
_hideTimeout = null;
|
||
|
|
}
|
||
|
|
for (const id of _revealTimeouts) clearTimeout(id);
|
||
|
|
_revealTimeouts = [];
|
||
|
|
|
||
|
|
container.innerHTML = '';
|
||
|
|
container.classList.add('visible');
|
||
|
|
|
||
|
|
let segments = mode === "letter" ? [...text] : text.split(' ');
|
||
|
|
let totalSteps = segments.length;
|
||
|
|
let delay = (totalDurationSeconds * 1000 * 0.7) / totalSteps;
|
||
|
|
|
||
|
|
segments.forEach((segment, i) => {
|
||
|
|
const span = document.createElement('span');
|
||
|
|
span.style.opacity = '0';
|
||
|
|
span.style.transition = 'opacity 0.3s ease';
|
||
|
|
span.textContent = mode === "word" ? segment + ' ' : segment;
|
||
|
|
|
||
|
|
container.appendChild(span);
|
||
|
|
|
||
|
|
const tid = setTimeout(() => {
|
||
|
|
span.style.opacity = '1';
|
||
|
|
}, i * delay);
|
||
|
|
_revealTimeouts.push(tid);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Hide after total duration
|
||
|
|
_hideTimeout = setTimeout(() => {
|
||
|
|
container.classList.remove('visible');
|
||
|
|
_hideTimeout = null;
|
||
|
|
}, totalDurationSeconds * 1000 + 900);
|
||
|
|
}
|