dsh-live-speak 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/RELEASE-NOTES.md CHANGED
@@ -204,6 +204,24 @@ dsh-live-speak
204
204
 
205
205
  ---
206
206
 
207
+ ## 1.0.5 更新说明
208
+
209
+ **修好了「本地语音」在部分电脑上显示「未检测到可用声线」**
210
+
211
+ 有人反馈:设置页的「声线」下拉是空的,写着「未检测到可用声线」,可电脑里明明装着中文语音。
212
+
213
+ 问题不在语音包,在插件自己。它原来靠系统 `PATH` 去找 PowerShell 来读声线清单,而有些环境里 `PATH` 是被裁剪过的(精简启动器、部分终端、或以自动化方式拉起的进程),`powershell.exe` 叫不到,探测就静默失败、返回空列表——设置页于是显示「没有声线」。
214
+
215
+ 现在改成**直接按绝对路径调用系统自带的 PowerShell**:先查 `SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe`,找不到才退回按名字找。不再依赖 `PATH`。
216
+
217
+ 修完之后这台机器上认到的声线是 5 条:惠惠、瑶瑶、康康(Windows 新版语音层),加上惠惠桌面版、Zira(旧版桌面层);默认挑中文的「瑶瑶」,本地合成一路正常出声。
218
+
219
+ **说明**:这个毛病只影响「本地语音」档和设置页的下拉列表。用「线上语音」的话声线是固定的晓晓,从来没受影响。
220
+
221
+ 当前版本:**1.0.5**
222
+
223
+ ---
224
+
207
225
  ## 1.0.4 更新说明
208
226
 
209
227
  **新增:语音服务长时间没响应时,卡片会告诉你它在重试**
@@ -224,7 +242,7 @@ dsh-live-speak
224
242
 
225
243
  **一条不变的原则**:合成失败不跳过。任何一段合成不出来,就一直重试到成功为止,宁可晚几秒开口,也不让内容缺一段。
226
244
 
227
- 当前版本:**1.0.4**
245
+ 历史版本:**1.0.4**
228
246
 
229
247
  ---
230
248
 
package/index.js CHANGED
@@ -80,6 +80,27 @@ const IS_WIN = process.platform === 'win32'
80
80
  const IS_MAC = process.platform === 'darwin'
81
81
  const IS_LINUX = process.platform === 'linux'
82
82
 
83
+ /**
84
+ * Windows 上调 PowerShell 一律走这个路径,不再让 execFile 按 PATH 去猜。
85
+ *
86
+ * 之前直接写 'powershell.exe':PATH 被裁剪的环境里(精简启动器、部分终端或
87
+ * 自动化工具拉起的进程,PATH 里可能没有 System32)会直接 ENOENT,探测被
88
+ * catch 成空清单,设置页就显示「未检测到可用声线」——系统里明明装着 Huihui。
89
+ * 面向公众发行时这种机器不少,所以固定用绝对路径,找不到才退回按名查找。
90
+ */
91
+ const POWERSHELL_EXE = (() => {
92
+ if (!IS_WIN) return 'powershell.exe'
93
+ const root = process.env.SystemRoot || process.env.windir || 'C:\\Windows'
94
+ const candidates = [
95
+ path.join(root, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'),
96
+ 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe',
97
+ ]
98
+ for (const candidate of candidates) {
99
+ if (fs.existsSync(candidate)) return candidate
100
+ }
101
+ return 'powershell.exe'
102
+ })()
103
+
83
104
  /**
84
105
  * 用户没指定声线时,按这个顺序挑一条。
85
106
  *
@@ -1290,11 +1311,15 @@ export function apply(ctx, config = {}) {
1290
1311
  const probeWinrtVoices = () => new Promise((resolve) => {
1291
1312
  ensureWinrtScripts()
1292
1313
  execFile(
1293
- 'powershell.exe',
1314
+ POWERSHELL_EXE,
1294
1315
  ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', WINRT_PROBE_PS1],
1295
1316
  { timeout: 20_000, windowsHide: true },
1296
1317
  (error, stdout) => {
1297
- if (error) { resolve([]); return }
1318
+ if (error) {
1319
+ log(`voice probe failed: ${String(error?.message ?? error).split('\n')[0]}`)
1320
+ resolve([])
1321
+ return
1322
+ }
1298
1323
  resolve(String(stdout || '')
1299
1324
  .split('\n')
1300
1325
  .map((line) => line.trim())
@@ -1317,11 +1342,15 @@ export function apply(ctx, config = {}) {
1317
1342
  ].join('; ')
1318
1343
  const probeSapiVoices = () => new Promise((resolve) => {
1319
1344
  execFile(
1320
- 'powershell.exe',
1345
+ POWERSHELL_EXE,
1321
1346
  ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', SAPI_PROBE_CMD],
1322
1347
  { timeout: 20_000, windowsHide: true },
1323
1348
  (error, stdout) => {
1324
- if (error) { resolve([]); return }
1349
+ if (error) {
1350
+ log(`voice probe failed: ${String(error?.message ?? error).split('\n')[0]}`)
1351
+ resolve([])
1352
+ return
1353
+ }
1325
1354
  resolve(String(stdout || '')
1326
1355
  .split('\n')
1327
1356
  .map((line) => line.trim())
@@ -1342,7 +1371,11 @@ export function apply(ctx, config = {}) {
1342
1371
  */
1343
1372
  const probeSayVoices = () => new Promise((resolve) => {
1344
1373
  execFile('say', ['-v', '?'], { timeout: 15_000 }, (error, stdout) => {
1345
- if (error) { resolve([]); return }
1374
+ if (error) {
1375
+ log(`voice probe failed: ${String(error?.message ?? error).split('\n')[0]}`)
1376
+ resolve([])
1377
+ return
1378
+ }
1346
1379
  const list = []
1347
1380
  for (const raw of String(stdout || '').split('\n')) {
1348
1381
  const hit = /^(.+?)\s+([a-zA-Z]{2}[_-][a-zA-Z]{2,3}(?:[_-][A-Za-z0-9]+)?)\s+#/u.exec(raw)
@@ -1488,7 +1521,7 @@ export function apply(ctx, config = {}) {
1488
1521
  return
1489
1522
  }
1490
1523
  execFile(
1491
- 'powershell.exe',
1524
+ POWERSHELL_EXE,
1492
1525
  [
1493
1526
  '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', WINRT_SYNTH_PS1,
1494
1527
  '-TextFile', txtPath, '-OutWav', wavPath, '-VoiceMatch', voice ? voice.name : '', '-Rate', rateExpr,
@@ -1746,7 +1779,7 @@ export function apply(ctx, config = {}) {
1746
1779
  '$s.Dispose()',
1747
1780
  ].join('; ')
1748
1781
  execFile(
1749
- 'powershell.exe',
1782
+ POWERSHELL_EXE,
1750
1783
  ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', script],
1751
1784
  {
1752
1785
  timeout: 25_000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-live-speak",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "用高保真神经语音实时播报模型输出(边生成边念),自带播放器,可随时暂停/恢复/停止。",
5
5
  "type": "module",
6
6
  "main": "./index.js",