refactor(web-test): add resolveEdgeTts() with fallback chain

Mirrors resolveFfmpeg() pattern: tries global/project-level import
first, then tools/tts/node_modules/, then throws error with install
instructions. Caches resolved module for subsequent calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-03-03 00:03:16 +03:00
parent e9b53505ac
commit 7f6ea32533
2 changed files with 32 additions and 5 deletions
+1 -1
View File
@@ -191,7 +191,7 @@ Add voiceover to recorded videos. Captions shown via `showCaption()` are automat
### Prerequisites
- **ffmpeg** — same as for video recording (ffprobe must be next to ffmpeg)
- **node-edge-tts** — `npm install node-edge-tts` (for Edge TTS provider, free, no API key)
- **node-edge-tts** — `npm install --prefix tools/tts node-edge-tts` (for Edge TTS provider, free, no API key). Also works if installed globally or at project level — the resolver tries multiple locations automatically
### Configuration in `.v8-project.json`
+31 -4
View File
@@ -3059,6 +3059,36 @@ function resolveFfmpeg(explicit) {
// ── TTS providers ──────────────────────────────────────────────────────────
/** Resolve node-edge-tts module: global install → tools/tts/ → error with instructions. */
let _edgeTtsModule = null;
async function resolveEdgeTts() {
if (_edgeTtsModule) return _edgeTtsModule;
// 1. Global/project-level install (standard Node resolution)
try {
_edgeTtsModule = await import('node-edge-tts');
return _edgeTtsModule;
} catch { /* fall through */ }
// 2. tools/tts/ relative to project root
const __fn = fileURLToPath(import.meta.url);
const projectRoot = pathResolve(dirname(__fn), '..', '..', '..', '..');
const localPath = pathResolve(projectRoot, 'tools', 'tts', 'node_modules', 'node-edge-tts', 'dist', 'edge-tts.js');
if (fsExistsSync(localPath)) {
try {
_edgeTtsModule = await import(pathToFileURL(localPath).href);
return _edgeTtsModule;
} catch { /* fall through */ }
}
// 3. Error with instructions
throw new Error(
'node-edge-tts not found. Install it:\n' +
' - npm install --prefix tools/tts node-edge-tts\n' +
' - or: npm install node-edge-tts (global/project-level)'
);
}
/**
* Edge TTS provider (free, no API key). Uses node-edge-tts package.
* @param {string} text — text to synthesize
@@ -3066,10 +3096,7 @@ function resolveFfmpeg(explicit) {
* @param {object} opts — { voice }
*/
async function edgeTtsProvider(text, outputPath, opts = {}) {
// Resolve from tools/node_modules/ (next to ffmpeg)
const __fn = fileURLToPath(import.meta.url);
const ttsModulePath = pathResolve(dirname(__fn), '..', '..', '..', '..', 'tools', 'tts', 'node_modules', 'node-edge-tts', 'dist', 'edge-tts.js');
const { EdgeTTS } = await import(pathToFileURL(ttsModulePath).href);
const { EdgeTTS } = await resolveEdgeTts();
const voice = opts.voice || 'ru-RU-DmitryNeural';
const tts = new EdgeTTS({ voice });
await Promise.race([