comfy-qa 2.2.0 → 2.3.0
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/package.json +1 -1
- package/src/recorder/post-mix.ts +28 -11
package/package.json
CHANGED
package/src/recorder/post-mix.ts
CHANGED
|
@@ -22,6 +22,11 @@ function srtTime(ms: number): string {
|
|
|
22
22
|
return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")},${String(msr).padStart(3, "0")}`;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** Format ms as WebVTT timestamp HH:MM:SS.mmm */
|
|
26
|
+
function vttTime(ms: number): string {
|
|
27
|
+
return srtTime(ms).replace(",", ".");
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
/** Generate SRT subtitle file from meta + initial offset */
|
|
26
31
|
function generateSrt(meta: Meta, offsetMs: number, outPath: string): void {
|
|
27
32
|
const lines: string[] = [];
|
|
@@ -38,6 +43,22 @@ function generateSrt(meta: Meta, offsetMs: number, outPath: string): void {
|
|
|
38
43
|
fs.writeFileSync(outPath, lines.join("\n"));
|
|
39
44
|
}
|
|
40
45
|
|
|
46
|
+
/** Generate WebVTT subtitle file from meta + initial offset (browser-native, no libass) */
|
|
47
|
+
export function generateVtt(meta: Meta, offsetMs: number, outPath: string): void {
|
|
48
|
+
const lines: string[] = ["WEBVTT", ""];
|
|
49
|
+
let cursor = offsetMs;
|
|
50
|
+
meta.segments.forEach((seg, i) => {
|
|
51
|
+
const start = cursor;
|
|
52
|
+
const end = cursor + seg.durationMs;
|
|
53
|
+
lines.push(String(i + 1));
|
|
54
|
+
lines.push(`${vttTime(start)} --> ${vttTime(end)}`);
|
|
55
|
+
lines.push(seg.text);
|
|
56
|
+
lines.push("");
|
|
57
|
+
cursor = end;
|
|
58
|
+
});
|
|
59
|
+
fs.writeFileSync(outPath, lines.join("\n"));
|
|
60
|
+
}
|
|
61
|
+
|
|
41
62
|
/**
|
|
42
63
|
* Mix audio + subtitles onto video.
|
|
43
64
|
* @param videoPath path to silent recorded video (webm/mp4)
|
|
@@ -63,19 +84,15 @@ export async function postMix(
|
|
|
63
84
|
console.log(` [post-mix] Overlaying audio (adelay=${offsetMs}ms)…`);
|
|
64
85
|
await $`ffmpeg -y -i ${videoPath} -i ${trackPath} -filter_complex ${`[1:a]adelay=${adelay}[aout]`} -map 0:v -map [aout] -c:v libx264 -preset fast -pix_fmt yuv420p -c:a aac -shortest ${audioMixed}`.quiet();
|
|
65
86
|
|
|
66
|
-
// Step 2: generate SRT
|
|
87
|
+
// Step 2: generate SRT + WebVTT (browser-native, no libass needed)
|
|
67
88
|
const srtPath = path.join(tmpDir, "narration.srt");
|
|
68
89
|
generateSrt(meta, offsetMs, srtPath);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log(` [post-mix] Burning subtitles…`);
|
|
73
|
-
// Escape path for ffmpeg subtitle filter
|
|
74
|
-
const escSrt = srtPath.replace(/\\/g, "/").replace(/:/g, "\\:");
|
|
75
|
-
await $`ffmpeg -y -i ${audioMixed} -vf ${`subtitles=${escSrt}:force_style='FontSize=18,Alignment=2,OutlineColour=&H80000000,BorderStyle=4,MarginV=30'`} -c:a copy ${outPath}`.quiet();
|
|
90
|
+
const vttPath = path.join(tmpDir, "narration.vtt");
|
|
91
|
+
generateVtt(meta, offsetMs, vttPath);
|
|
92
|
+
console.log(` [post-mix] Subtitles → ${srtPath} + ${vttPath}`);
|
|
76
93
|
|
|
77
|
-
//
|
|
78
|
-
|
|
94
|
+
// Step 3: rename audio-mixed to final output (subtitles served as sidecar .vtt)
|
|
95
|
+
fs.renameSync(audioMixed, outPath);
|
|
79
96
|
|
|
80
|
-
console.log(` [post-mix] Final video → ${outPath}`);
|
|
97
|
+
console.log(` [post-mix] Final video → ${outPath} (subtitles: ${vttPath})`);
|
|
81
98
|
}
|