fix: TTS voices — retry 10s, message on failure, refresh button
- Retry loop extended to 10s (50×200ms) for slow Android WebViews - Show 'Nessuna voce disponibile' after timeout instead of infinite loader - Show 'Voce non supportata dal browser' if speechSynthesis missing - Reset to loading state on each settings open (fixes stale empty select) - Add refresh button ↺ to force-reload voices manually
This commit is contained in:
+24
-13
@@ -9279,7 +9279,15 @@ function onTtsEngineChange(engine) {
|
||||
/** Populate voice selector from Web Speech API. Called on settings load and on voiceschanged. */
|
||||
function _initBrowserTtsVoices(selectedVoice) {
|
||||
const sel = document.getElementById('setting-tts-voice');
|
||||
if (!sel || !window.speechSynthesis) return;
|
||||
if (!sel) return;
|
||||
|
||||
if (!window.speechSynthesis) {
|
||||
sel.innerHTML = '<option value="">— Voce non supportata dal browser —</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset to loading state each time (settings page may be re-opened)
|
||||
sel.innerHTML = '<option value="">— Caricamento voci… —</option>';
|
||||
|
||||
const populate = () => {
|
||||
const voices = window.speechSynthesis.getVoices();
|
||||
@@ -9291,7 +9299,7 @@ function _initBrowserTtsVoices(selectedVoice) {
|
||||
sel.innerHTML = sorted.map(v =>
|
||||
`<option value="${v.name}" ${v.name === selectedVoice ? 'selected' : ''}>${v.name} (${v.lang})${v.localService ? '' : ' ☁️'}</option>`
|
||||
).join('');
|
||||
// Auto-select Paola if no preference and it exists
|
||||
// Auto-select first Italian voice if no preference set
|
||||
if (!selectedVoice) {
|
||||
const paola = sorted.find(v => v.name === 'Paola');
|
||||
const firstIt = sorted.find(v => v.lang.startsWith('it'));
|
||||
@@ -9301,23 +9309,26 @@ function _initBrowserTtsVoices(selectedVoice) {
|
||||
return true;
|
||||
};
|
||||
|
||||
// Some browsers (Chrome) load voices async: onvoiceschanged fires once they're ready.
|
||||
// But if voices are already loaded, onvoiceschanged never fires → try immediately too.
|
||||
// Additionally, onvoiceschanged may have already fired before we assign the handler
|
||||
// (race condition), so we also poll with short retries as fallback.
|
||||
if (!populate()) {
|
||||
// Register the event handler for browsers that fire it
|
||||
if (window.speechSynthesis.onvoiceschanged !== undefined) {
|
||||
// Try immediately (voices already cached from previous call)
|
||||
if (populate()) return;
|
||||
|
||||
// onvoiceschanged fires in Firefox / some Chrome versions
|
||||
window.speechSynthesis.onvoiceschanged = () => { populate(); };
|
||||
}
|
||||
// Fallback retry loop: try every 200ms for up to 4 seconds
|
||||
|
||||
// Polling fallback: Chrome/WebView loads voices async (up to ~3s on desktop, longer on Android)
|
||||
let tries = 0;
|
||||
const interval = setInterval(() => {
|
||||
tries++;
|
||||
if (populate() || tries >= 20) clearInterval(interval);
|
||||
}, 200);
|
||||
if (populate()) {
|
||||
clearInterval(interval);
|
||||
} else if (tries >= 50) { // 50 × 200ms = 10s
|
||||
clearInterval(interval);
|
||||
if (!window.speechSynthesis.getVoices().length) {
|
||||
sel.innerHTML = '<option value="">— Nessuna voce disponibile su questo dispositivo —</option>';
|
||||
}
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
/** Speak text using the browser Web Speech API (offline). */
|
||||
function _speakBrowser(text) {
|
||||
|
||||
+5
-2
@@ -930,10 +930,13 @@
|
||||
<div id="tts-browser-section">
|
||||
<div class="form-group">
|
||||
<label>🗣️ Voce</label>
|
||||
<select id="setting-tts-voice" class="form-input">
|
||||
<div style="display:flex;gap:8px;align-items:center">
|
||||
<select id="setting-tts-voice" class="form-input" style="flex:1">
|
||||
<option value="">— Caricamento voci… —</option>
|
||||
</select>
|
||||
<p class="settings-hint">Le voci disponibili dipendono dal sistema operativo e dal browser. Su macOS/iOS è disponibile la voce <strong>Paola</strong> (italiano).</p>
|
||||
<button type="button" class="btn btn-secondary" style="padding:8px 12px;white-space:nowrap;flex-shrink:0" onclick="_initBrowserTtsVoices(document.getElementById('setting-tts-voice').value)">↺</button>
|
||||
</div>
|
||||
<p class="settings-hint">Le voci disponibili dipendono dal sistema operativo e dal browser. Su macOS/iOS è disponibile la voce <strong>Paola</strong> (italiano). Premi ↺ se la lista non si carica.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>⚡ Velocità: <span id="tts-rate-label">1.0</span>×</label>
|
||||
|
||||
Reference in New Issue
Block a user