diff --git a/skills-manifest.json b/skills-manifest.json index e411541e93..7706e7f56f 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -50,8 +50,8 @@ "files": 12 }, "media-use": { - "hash": "08a544dfaca9e846", - "files": 158 + "hash": "a7208c47707dfab0", + "files": 159 }, "motion-graphics": { "hash": "32641ae2b94c4a8f", diff --git a/skills/media-use/audio/scripts/audio.mjs b/skills/media-use/audio/scripts/audio.mjs index 167eb679ca..c15ec61ad9 100644 --- a/skills/media-use/audio/scripts/audio.mjs +++ b/skills/media-use/audio/scripts/audio.mjs @@ -39,7 +39,7 @@ // the generate path it is spawned detached (bgm_pending:true) — run wait-bgm.mjs // before assembling. -import { existsSync, mkdirSync, readFileSync } from "node:fs"; +import { existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { heygenAuthHeaders, heygenCredential, loadEnvFromDir } from "./lib/heygen.mjs"; @@ -68,6 +68,7 @@ const die = (m) => { process.exit(1); }; const r3 = (x) => Number(x.toFixed(3)); +const lineText = (line) => String(line.text ?? "").trim(); // Two independent reports of an unbounded Promise.all over TTS lines // overwhelming a machine: one OOM'd 12/13 concurrent Kokoro TTS + @@ -140,7 +141,7 @@ if (only.has("tts") && lines.length) { console.error(`· tts: ${ttsProvider} · voice ${voiceId} · ${lines.length} line(s)`); const synthLine = async (line) => { const id = String(line.id); - const text = String(line.text ?? "").trim(); + const text = lineText(line); if (!text) { anomalies.push(`line ${id}: empty text — skipped`); return null; @@ -174,6 +175,43 @@ if (only.has("tts") && lines.length) { for (const v of voices) console.error(` voice ${v.id}: ${v.path} (${v.duration_s}s, ${v.words.length} words)`); } + +// ── reconcile externally-supplied narration ────────────────────────────────── +// A narration WAV can land in assets/voice/.wav without ever going +// through the synthLine loop above — hand-placed, copied over from another +// run, or left behind by one that generated the file but didn't finish +// registering it. voices[] only ever grows inside that loop, so such a file +// is invisible to every consumer that trusts voices[] (assemble-index.mjs's +//