From 98faed320a53e40ec9b6025acd84050520c32e11 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Sat, 26 Apr 2025 15:00:09 +0800 Subject: [PATCH] feat: add more English voices for all en locales, closes #966 (#969) --- .../src/services/tts/EdgeTTSClient.ts | 23 ++++++++++++++++++- .../src/services/tts/WebSpeechClient.ts | 6 ++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/readest-app/src/services/tts/EdgeTTSClient.ts b/apps/readest-app/src/services/tts/EdgeTTSClient.ts index 501c53e7..60234b37 100644 --- a/apps/readest-app/src/services/tts/EdgeTTSClient.ts +++ b/apps/readest-app/src/services/tts/EdgeTTSClient.ts @@ -245,7 +245,28 @@ export class EdgeTTSClient implements TTSClient { } const locale = lang === 'en' ? getUserLocale(lang) || lang : lang; const voices = await this.getAllVoices(); - return voices.filter((v) => v.lang.startsWith(locale)); + return voices + .filter( + (v) => v.lang.startsWith(locale) || (lang === 'en' && ['en-US', 'en-GB'].includes(v.lang)), + ) + .sort((a, b) => { + const aRegion = a.lang.split('-')[1] || ''; + const bRegion = b.lang.split('-')[1] || ''; + if (aRegion === bRegion) { + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; + } + if (aRegion === 'CN') return -1; + if (bRegion === 'CN') return 1; + if (aRegion === 'TW') return -1; + if (bRegion === 'TW') return 1; + if (aRegion === 'HK') return -1; + if (bRegion === 'HK') return 1; + if (aRegion === 'US') return -1; + if (bRegion === 'US') return 1; + if (aRegion === 'GB') return -1; + if (bRegion === 'GB') return 1; + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; + }); } getGranularities(): TTSGranularity[] { diff --git a/apps/readest-app/src/services/tts/WebSpeechClient.ts b/apps/readest-app/src/services/tts/WebSpeechClient.ts index 92ee07fd..e9540ffe 100644 --- a/apps/readest-app/src/services/tts/WebSpeechClient.ts +++ b/apps/readest-app/src/services/tts/WebSpeechClient.ts @@ -311,7 +311,11 @@ export class WebSpeechClient implements TTSClient { return BLACKLISTED_VOICES.some((name) => voice.name.includes(name)) === false; }; const filteredVoices = this.#voices - .filter((voice) => voice.lang.startsWith(locale)) + .filter( + (voice) => + voice.lang.startsWith(locale) || + (lang === 'en' && ['en-US', 'en-GB'].includes(voice.lang)), + ) .filter((voice) => isValidVoice(voice.voiceURI || '')) .filter(isNotBlacklisted); const seenIds = new Set();