127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
export default function handleArticleReader() {
|
|
const button = document.getElementById('listen-article');
|
|
const article = document.querySelector('.article-content');
|
|
|
|
// Paramètres fixes définis dans le code
|
|
const speechSettings = {
|
|
rate: 1.2, // Vitesse de lecture (0.1 à 2)
|
|
pitch: 1.1, // Tonalité (0 à 2)
|
|
volume: 1, // Volume (0 à 1)
|
|
};
|
|
|
|
let utterance: SpeechSynthesisUtterance;
|
|
let voices: SpeechSynthesisVoice[] = [];
|
|
let thomasVoice: SpeechSynthesisVoice | null = null;
|
|
|
|
// Charger les voix et trouver Thomas
|
|
function loadVoices() {
|
|
voices = speechSynthesis.getVoices();
|
|
|
|
// Chercher la voix Thomas (peut être "Thomas" ou contenir "Thomas")
|
|
thomasVoice =
|
|
voices.find(
|
|
(voice) => voice.name.toLowerCase().includes('thomas') || voice.name === 'Thomas'
|
|
) || null;
|
|
|
|
// Si Thomas n'est pas trouvé, prendre une voix française par défaut
|
|
if (!thomasVoice) {
|
|
thomasVoice = voices.find((voice) => voice.lang.startsWith('fr')) || null;
|
|
}
|
|
}
|
|
|
|
// Charger les voix au démarrage et quand elles changent
|
|
loadVoices();
|
|
speechSynthesis.onvoiceschanged = loadVoices;
|
|
|
|
// Variables pour le highlighting
|
|
let originalContent = '';
|
|
let words: string[] = [];
|
|
let currentWordIndex = 0;
|
|
|
|
function highlightWord(index: number) {
|
|
if (!article || index >= words.length) return;
|
|
|
|
// Restaurer le contenu original si c'est le premier mot
|
|
if (index === 0) {
|
|
article.innerHTML = originalContent;
|
|
}
|
|
|
|
// Créer le nouveau HTML avec le mot highlighted
|
|
const highlightedWords = words.map((word, i) => {
|
|
if (i === index) {
|
|
return `<span class="speech-highlight" style="background-color: yellow; padding: 2px 4px; border-radius: 3px;">${word}</span>`;
|
|
}
|
|
return word;
|
|
});
|
|
|
|
article.innerHTML = highlightedWords.join(' ');
|
|
}
|
|
|
|
function removeHighlight() {
|
|
if (article && originalContent) {
|
|
article.innerHTML = originalContent;
|
|
}
|
|
}
|
|
|
|
function createUtterance(text: string): SpeechSynthesisUtterance {
|
|
// Sauvegarder le contenu original et préparer les mots
|
|
originalContent = article ? article.innerHTML : '';
|
|
words = text.split(/\s+/).filter((word) => word.trim().length > 0);
|
|
currentWordIndex = 0;
|
|
|
|
utterance = new SpeechSynthesisUtterance(text);
|
|
utterance.lang = 'fr-FR';
|
|
|
|
// Appliquer les paramètres fixes
|
|
utterance.rate = speechSettings.rate;
|
|
utterance.pitch = speechSettings.pitch;
|
|
utterance.volume = speechSettings.volume;
|
|
|
|
// Utiliser Thomas par défaut
|
|
if (thomasVoice) {
|
|
utterance.voice = thomasVoice;
|
|
}
|
|
|
|
// Event pour highlighter les mots pendant la lecture
|
|
utterance.onboundary = (event) => {
|
|
if (event.name === 'word') {
|
|
highlightWord(currentWordIndex);
|
|
currentWordIndex++;
|
|
}
|
|
};
|
|
|
|
utterance.onend = () => {
|
|
button.textContent = '🔊 Lire en vocal';
|
|
removeHighlight();
|
|
currentWordIndex = 0;
|
|
};
|
|
|
|
utterance.onerror = (event) => {
|
|
console.error('Erreur lors de la lecture:', event);
|
|
button.textContent = '🔊 Lire en vocal';
|
|
removeHighlight();
|
|
currentWordIndex = 0;
|
|
};
|
|
|
|
return utterance;
|
|
}
|
|
|
|
button?.addEventListener('click', () => {
|
|
if (speechSynthesis.speaking) {
|
|
speechSynthesis.cancel();
|
|
button.classList.remove('is-active');
|
|
removeHighlight(); // Retirer le highlight quand on arrête
|
|
currentWordIndex = 0;
|
|
} else {
|
|
if (article) {
|
|
const text = (article as HTMLElement).innerText.trim();
|
|
if (text) {
|
|
createUtterance(text);
|
|
speechSynthesis.speak(utterance);
|
|
button.classList.add('is-active');
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|