Skip to content

Commit 5aa78e2

Browse files
authored
Store selected TTS voice in localStorage (#1241)
1 parent 650c9f7 commit 5aa78e2

2 files changed

Lines changed: 42 additions & 3 deletions

File tree

src/plugins/tts/AbstractTTSEngine.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ export default class AbstractTTSEngine {
142142
// MS Edge fires voices changed randomly very often
143143
this.events.off('voiceschanged', this.updateBestVoice);
144144
this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
145+
// if the current book has a language set, store the selected voice with the book language as a suffix
146+
if (this.opts.bookLanguage) {
147+
localStorage.setItem(`BRtts-voice-${this.opts.bookLanguage}`, this.voice.voiceURI);
148+
}
145149
if (this.activeSound) this.activeSound.setVoice(this.voice);
146150
}
147151

@@ -221,17 +225,32 @@ export default class AbstractTTSEngine {
221225
// user languages that match the book language
222226
const matchingUserLangs = userLanguages.filter(lang => lang.startsWith(bookLanguage));
223227

224-
// Try to find voices that intersect these two sets
225-
return AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices) ||
228+
// First try to find the last chosen voice from localStorage for the current book language
229+
return AbstractTTSEngine.getMatchingStoredVoice(bookLangVoices, bookLanguage)
230+
// Try to find voices that intersect these two sets
231+
|| AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices)
226232
// no user languages match the books; let's return the best voice for the book language
227-
(bookLangVoices.find(v => v.default) || bookLangVoices[0])
233+
|| (bookLangVoices.find(v => v.default) || bookLangVoices[0])
228234
// No voices match the book language? let's find a voice in the user's language
229235
// and ignore book lang
230236
|| AbstractTTSEngine.getMatchingVoice(userLanguages, voices)
231237
// C'mon! Ok, just read with whatever we got!
232238
|| (voices.find(v => v.default) || voices[0]);
233239
}
234240

241+
/**
242+
* @private
243+
* Get the voice last selected by the user for the book language from localStorage.
244+
* Returns undefined if no voice is stored or found.
245+
* @param {SpeechSynthesisVoice[]} voices browser voices to choose from
246+
* @param {ISO6391} bookLanguage book language to look for
247+
* @return {SpeechSynthesisVoice | undefined}
248+
*/
249+
static getMatchingStoredVoice(voices, bookLanguage) {
250+
const storedVoice = localStorage.getItem(`BRtts-voice-${bookLanguage}`);
251+
return (storedVoice ? voices.find(v => v.voiceURI === storedVoice) : undefined);
252+
}
253+
235254
/**
236255
* @private
237256
* Get the best voice that matches one of the BCP47 languages (order by preference)

tests/jest/plugins/tts/AbstractTTSEngine.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,26 @@ for (const dummyVoice of [dummyVoiceHyphens, dummyVoiceUnderscores]) {
111111

112112
expect(getBestBookVoice(voices, 'en', ['en-CA', 'en'])).toBe(voices[0]);
113113
});
114+
115+
test('choose stored language from localStorage', () => {
116+
const voices = [
117+
dummyVoice({lang: "en-US", voiceURI: "English US", default: true}),
118+
dummyVoice({lang: "en-GB", voiceURI: "English GB"}),
119+
dummyVoice({lang: "en-CA", voiceURI: "English CA"}),
120+
];
121+
class DummyEngine extends AbstractTTSEngine {
122+
getVoices() { return voices; }
123+
}
124+
const ttsEngine = new DummyEngine({...DUMMY_TTS_ENGINE_OPTS, bookLanguage: 'en'});
125+
// simulates setting default voice on tts startup
126+
ttsEngine.updateBestVoice();
127+
// simulates user choosing a voice that matches the bookLanguage
128+
// voice will be stored in localStorage
129+
ttsEngine.setVoice(voices[2].voiceURI);
130+
131+
// expecting the voice to be selected by getMatchingStoredVoice and returned as best voice
132+
expect(getBestBookVoice(voices, 'en', [])).toBe(voices[2]);
133+
});
114134
});
115135
}
116136

0 commit comments

Comments
 (0)