playwright-recast 0.1.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/LICENSE +21 -0
- package/README.md +282 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +139 -0
- package/dist/cli.js.map +1 -0
- package/dist/filter/step-filter.d.ts +7 -0
- package/dist/filter/step-filter.d.ts.map +1 -0
- package/dist/filter/step-filter.js +23 -0
- package/dist/filter/step-filter.js.map +1 -0
- package/dist/helpers.d.ts +41 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +73 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/parse/jsonl-parser.d.ts +87 -0
- package/dist/parse/jsonl-parser.d.ts.map +1 -0
- package/dist/parse/jsonl-parser.js +17 -0
- package/dist/parse/jsonl-parser.js.map +1 -0
- package/dist/parse/trace-parser.d.ts +6 -0
- package/dist/parse/trace-parser.d.ts.map +1 -0
- package/dist/parse/trace-parser.js +149 -0
- package/dist/parse/trace-parser.js.map +1 -0
- package/dist/parse/zip-reader.d.ts +21 -0
- package/dist/parse/zip-reader.d.ts.map +1 -0
- package/dist/parse/zip-reader.js +45 -0
- package/dist/parse/zip-reader.js.map +1 -0
- package/dist/pipeline/executor.d.ts +16 -0
- package/dist/pipeline/executor.d.ts.map +1 -0
- package/dist/pipeline/executor.js +283 -0
- package/dist/pipeline/executor.js.map +1 -0
- package/dist/pipeline/pipeline.d.ts +79 -0
- package/dist/pipeline/pipeline.d.ts.map +1 -0
- package/dist/pipeline/pipeline.js +105 -0
- package/dist/pipeline/pipeline.js.map +1 -0
- package/dist/pipeline/stages.d.ts +49 -0
- package/dist/pipeline/stages.d.ts.map +1 -0
- package/dist/pipeline/stages.js +2 -0
- package/dist/pipeline/stages.js.map +1 -0
- package/dist/render/renderer.d.ts +22 -0
- package/dist/render/renderer.d.ts.map +1 -0
- package/dist/render/renderer.js +174 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/speed/classifiers.d.ts +8 -0
- package/dist/speed/classifiers.d.ts.map +1 -0
- package/dist/speed/classifiers.js +38 -0
- package/dist/speed/classifiers.js.map +1 -0
- package/dist/speed/speed-processor.d.ts +9 -0
- package/dist/speed/speed-processor.d.ts.map +1 -0
- package/dist/speed/speed-processor.js +97 -0
- package/dist/speed/speed-processor.js.map +1 -0
- package/dist/speed/time-remap.d.ts +12 -0
- package/dist/speed/time-remap.d.ts.map +1 -0
- package/dist/speed/time-remap.js +44 -0
- package/dist/speed/time-remap.js.map +1 -0
- package/dist/subtitles/srt-parser.d.ts +4 -0
- package/dist/subtitles/srt-parser.d.ts.map +1 -0
- package/dist/subtitles/srt-parser.js +28 -0
- package/dist/subtitles/srt-parser.js.map +1 -0
- package/dist/subtitles/srt-writer.d.ts +4 -0
- package/dist/subtitles/srt-writer.d.ts.map +1 -0
- package/dist/subtitles/srt-writer.js +28 -0
- package/dist/subtitles/srt-writer.js.map +1 -0
- package/dist/subtitles/subtitle-generator.d.ts +9 -0
- package/dist/subtitles/subtitle-generator.d.ts.map +1 -0
- package/dist/subtitles/subtitle-generator.js +30 -0
- package/dist/subtitles/subtitle-generator.js.map +1 -0
- package/dist/subtitles/vtt-writer.d.ts +4 -0
- package/dist/subtitles/vtt-writer.d.ts.map +1 -0
- package/dist/subtitles/vtt-writer.js +28 -0
- package/dist/subtitles/vtt-writer.js.map +1 -0
- package/dist/types/render.d.ts +41 -0
- package/dist/types/render.d.ts.map +1 -0
- package/dist/types/render.js +17 -0
- package/dist/types/render.js.map +1 -0
- package/dist/types/speed.d.ts +54 -0
- package/dist/types/speed.d.ts.map +1 -0
- package/dist/types/speed.js +2 -0
- package/dist/types/speed.js.map +1 -0
- package/dist/types/subtitle.d.ts +31 -0
- package/dist/types/subtitle.d.ts.map +1 -0
- package/dist/types/subtitle.js +2 -0
- package/dist/types/subtitle.js.map +1 -0
- package/dist/types/trace.d.ts +103 -0
- package/dist/types/trace.d.ts.map +1 -0
- package/dist/types/trace.js +4 -0
- package/dist/types/trace.js.map +1 -0
- package/dist/types/voiceover.d.ts +42 -0
- package/dist/types/voiceover.d.ts.map +1 -0
- package/dist/types/voiceover.js +2 -0
- package/dist/types/voiceover.js.map +1 -0
- package/dist/utils/ffmpeg.d.ts +7 -0
- package/dist/utils/ffmpeg.d.ts.map +1 -0
- package/dist/utils/ffmpeg.js +24 -0
- package/dist/utils/ffmpeg.js.map +1 -0
- package/dist/voiceover/providers/elevenlabs.d.ts +12 -0
- package/dist/voiceover/providers/elevenlabs.d.ts.map +1 -0
- package/dist/voiceover/providers/elevenlabs.js +55 -0
- package/dist/voiceover/providers/elevenlabs.js.map +1 -0
- package/dist/voiceover/providers/openai.d.ts +14 -0
- package/dist/voiceover/providers/openai.d.ts.map +1 -0
- package/dist/voiceover/providers/openai.js +53 -0
- package/dist/voiceover/providers/openai.js.map +1 -0
- package/dist/voiceover/voiceover-processor.d.ts +9 -0
- package/dist/voiceover/voiceover-processor.d.ts.map +1 -0
- package/dist/voiceover/voiceover-processor.js +88 -0
- package/dist/voiceover/voiceover-processor.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/types/trace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../src/types/trace.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,EAAiB,CAAA;AAC1B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { SubtitleEntry, SubtitledTrace } from './subtitle';
|
|
2
|
+
/** A chunk of synthesized audio */
|
|
3
|
+
export interface AudioSegment {
|
|
4
|
+
data: Buffer;
|
|
5
|
+
durationMs: number;
|
|
6
|
+
format: {
|
|
7
|
+
sampleRate: number;
|
|
8
|
+
channels: number;
|
|
9
|
+
codec: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** Options for a single TTS synthesis call */
|
|
13
|
+
export interface TtsOptions {
|
|
14
|
+
voice?: string;
|
|
15
|
+
speed?: number;
|
|
16
|
+
format?: 'mp3' | 'wav' | 'opus' | 'pcm';
|
|
17
|
+
locale?: string;
|
|
18
|
+
}
|
|
19
|
+
/** The contract every TTS provider must implement */
|
|
20
|
+
export interface TtsProvider {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
synthesize(text: string, options?: TtsOptions): Promise<AudioSegment>;
|
|
23
|
+
estimateDurationMs(text: string, options?: TtsOptions): number;
|
|
24
|
+
isAvailable(): Promise<boolean>;
|
|
25
|
+
dispose(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
/** A voiceover entry matched to a subtitle */
|
|
28
|
+
export interface VoiceoverEntry {
|
|
29
|
+
subtitle: SubtitleEntry;
|
|
30
|
+
audio: AudioSegment;
|
|
31
|
+
outputStartMs: number;
|
|
32
|
+
outputEndMs: number;
|
|
33
|
+
}
|
|
34
|
+
/** Trace after voiceover has been generated */
|
|
35
|
+
export interface VoiceoveredTrace extends SubtitledTrace {
|
|
36
|
+
voiceover: {
|
|
37
|
+
entries: VoiceoverEntry[];
|
|
38
|
+
audioTrackPath: string;
|
|
39
|
+
totalDurationMs: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=voiceover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceover.d.ts","sourceRoot":"","sources":["../../src/types/voiceover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE/D,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACrE,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;IAC9D,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,aAAa,CAAA;IACvB,KAAK,EAAE,YAAY,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,+CAA+C;AAC/C,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,SAAS,EAAE;QACT,OAAO,EAAE,cAAc,EAAE,CAAA;QACzB,cAAc,EAAE,MAAM,CAAA;QACtB,eAAe,EAAE,MAAM,CAAA;KACxB,CAAA;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceover.js","sourceRoot":"","sources":["../../src/types/voiceover.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assert that both `ffmpeg` and `ffprobe` are available on the system PATH.
|
|
3
|
+
* Throws a descriptive error if either binary is missing, so the user gets
|
|
4
|
+
* a clear message instead of a cryptic ENOENT later in the pipeline.
|
|
5
|
+
*/
|
|
6
|
+
export declare function assertFfmpegAvailable(): void;
|
|
7
|
+
//# sourceMappingURL=ffmpeg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../../src/utils/ffmpeg.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAiB5C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Assert that both `ffmpeg` and `ffprobe` are available on the system PATH.
|
|
4
|
+
* Throws a descriptive error if either binary is missing, so the user gets
|
|
5
|
+
* a clear message instead of a cryptic ENOENT later in the pipeline.
|
|
6
|
+
*/
|
|
7
|
+
export function assertFfmpegAvailable() {
|
|
8
|
+
for (const bin of ['ffmpeg', 'ffprobe']) {
|
|
9
|
+
try {
|
|
10
|
+
execFileSync(bin, ['-version'], { stdio: 'pipe' });
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
const code = error.code;
|
|
14
|
+
if (code === 'ENOENT') {
|
|
15
|
+
throw new Error(`"${bin}" is not installed or not on PATH. ` +
|
|
16
|
+
`Install ffmpeg (https://ffmpeg.org/download.html) and ensure both ffmpeg and ffprobe are accessible.`);
|
|
17
|
+
}
|
|
18
|
+
// If the binary exists but returned a non-zero exit code, that's fine —
|
|
19
|
+
// it means the binary is present. Some ffmpeg builds exit(1) for -version
|
|
20
|
+
// on certain platforms, which is acceptable.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=ffmpeg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../src/utils/ffmpeg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QACjD,IAAI,CAAC;YACH,YAAY,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACpD,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAA;YAClD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CACb,IAAI,GAAG,qCAAqC;oBAC1C,sGAAsG,CACzG,CAAA;YACH,CAAC;YACD,wEAAwE;YACxE,0EAA0E;YAC1E,6CAA6C;QAC/C,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TtsProvider } from '../../types/voiceover';
|
|
2
|
+
export interface ElevenLabsProviderConfig {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
voiceId?: string;
|
|
5
|
+
modelId?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* ElevenLabs TTS provider.
|
|
9
|
+
* Requires `@elevenlabs/elevenlabs-js` as a peer dependency.
|
|
10
|
+
*/
|
|
11
|
+
export declare function ElevenLabsProvider(config?: ElevenLabsProviderConfig): TtsProvider;
|
|
12
|
+
//# sourceMappingURL=elevenlabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevenlabs.d.ts","sourceRoot":"","sources":["../../../src/voiceover/providers/elevenlabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAA;AAElF,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAgBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,wBAA6B,GAAG,WAAW,CAsDrF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const DEFAULT_VOICE_ID = 'onwK4e9ZLuTAKqWW03F9'; // Daniel
|
|
2
|
+
const DEFAULT_MODEL_ID = 'eleven_multilingual_v2';
|
|
3
|
+
/**
|
|
4
|
+
* ElevenLabs TTS provider.
|
|
5
|
+
* Requires `@elevenlabs/elevenlabs-js` as a peer dependency.
|
|
6
|
+
*/
|
|
7
|
+
export function ElevenLabsProvider(config = {}) {
|
|
8
|
+
const apiKey = config.apiKey ?? process.env.ELEVENLABS_API_KEY;
|
|
9
|
+
const voiceId = config.voiceId ?? DEFAULT_VOICE_ID;
|
|
10
|
+
const modelId = config.modelId ?? DEFAULT_MODEL_ID;
|
|
11
|
+
let client = null;
|
|
12
|
+
async function getClient() {
|
|
13
|
+
if (client)
|
|
14
|
+
return client;
|
|
15
|
+
const { ElevenLabsClient: ELClient } = await import('@elevenlabs/elevenlabs-js');
|
|
16
|
+
client = new ELClient({ apiKey });
|
|
17
|
+
return client;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
name: 'elevenlabs',
|
|
21
|
+
async synthesize(text, _options) {
|
|
22
|
+
const el = await getClient();
|
|
23
|
+
const audio = await el.textToSpeech.convert(voiceId, {
|
|
24
|
+
text,
|
|
25
|
+
modelId,
|
|
26
|
+
outputFormat: 'mp3_44100_128',
|
|
27
|
+
});
|
|
28
|
+
const reader = audio.getReader();
|
|
29
|
+
const chunks = [];
|
|
30
|
+
while (true) {
|
|
31
|
+
const { done, value } = await reader.read();
|
|
32
|
+
if (done)
|
|
33
|
+
break;
|
|
34
|
+
chunks.push(value);
|
|
35
|
+
}
|
|
36
|
+
const data = Buffer.concat(chunks);
|
|
37
|
+
return {
|
|
38
|
+
data,
|
|
39
|
+
durationMs: 0, // Will be measured by voiceover-processor via ffprobe
|
|
40
|
+
format: { sampleRate: 44100, channels: 1, codec: 'mp3' },
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
estimateDurationMs(text) {
|
|
44
|
+
const words = text.split(/\s+/).length;
|
|
45
|
+
return (words / 150) * 60_000;
|
|
46
|
+
},
|
|
47
|
+
async isAvailable() {
|
|
48
|
+
return !!apiKey;
|
|
49
|
+
},
|
|
50
|
+
async dispose() {
|
|
51
|
+
client = null;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=elevenlabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../../src/voiceover/providers/elevenlabs.ts"],"names":[],"mappings":"AAQA,MAAM,gBAAgB,GAAG,sBAAsB,CAAA,CAAC,SAAS;AACzD,MAAM,gBAAgB,GAAG,wBAAwB,CAAA;AAajD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAmC,EAAE;IACtE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,gBAAgB,CAAA;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,gBAAgB,CAAA;IAElD,IAAI,MAAM,GAA4B,IAAI,CAAA;IAE1C,KAAK,UAAU,SAAS;QACtB,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QACzB,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAA;QAChF,MAAM,GAAG,IAAI,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAgC,CAAA;QAChE,OAAO,MAAM,CAAA;IACf,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;QAElB,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,QAAqB;YAClD,MAAM,EAAE,GAAG,MAAM,SAAS,EAAE,CAAA;YAC5B,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE;gBACnD,IAAI;gBACJ,OAAO;gBACP,YAAY,EAAE,eAAe;aAC9B,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAA;YAChC,MAAM,MAAM,GAAiB,EAAE,CAAA;YAC/B,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;gBAC3C,IAAI,IAAI;oBAAE,MAAK;gBACf,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAClC,OAAO;gBACL,IAAI;gBACJ,UAAU,EAAE,CAAC,EAAE,sDAAsD;gBACrE,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;aACzD,CAAA;QACH,CAAC;QAED,kBAAkB,CAAC,IAAY;YAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;YACtC,OAAO,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,MAAM,CAAA;QAC/B,CAAC;QAED,KAAK,CAAC,WAAW;YACf,OAAO,CAAC,CAAC,MAAM,CAAA;QACjB,CAAC;QAED,KAAK,CAAC,OAAO;YACX,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TtsProvider } from '../../types/voiceover';
|
|
2
|
+
export interface OpenAIProviderConfig {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
voice?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
speed?: number;
|
|
7
|
+
instructions?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* OpenAI TTS provider.
|
|
11
|
+
* Requires `openai` as a peer dependency.
|
|
12
|
+
*/
|
|
13
|
+
export declare function OpenAIProvider(config?: OpenAIProviderConfig): TtsProvider;
|
|
14
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/voiceover/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAA;AAElF,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAWD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,WAAW,CAsD7E"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI TTS provider.
|
|
3
|
+
* Requires `openai` as a peer dependency.
|
|
4
|
+
*/
|
|
5
|
+
export function OpenAIProvider(config = {}) {
|
|
6
|
+
const apiKey = config.apiKey ?? process.env.OPENAI_API_KEY;
|
|
7
|
+
const voice = config.voice ?? 'nova';
|
|
8
|
+
const model = config.model ?? 'gpt-4o-mini-tts';
|
|
9
|
+
const speed = config.speed ?? 1.0;
|
|
10
|
+
const instructions = config.instructions;
|
|
11
|
+
let client = null;
|
|
12
|
+
async function getClient() {
|
|
13
|
+
if (client)
|
|
14
|
+
return client;
|
|
15
|
+
const OpenAI = (await import('openai')).default;
|
|
16
|
+
client = new OpenAI({ apiKey });
|
|
17
|
+
return client;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
name: 'openai',
|
|
21
|
+
async synthesize(text, options) {
|
|
22
|
+
const openai = await getClient();
|
|
23
|
+
const params = {
|
|
24
|
+
model,
|
|
25
|
+
voice: options?.voice ?? voice,
|
|
26
|
+
input: text,
|
|
27
|
+
speed: options?.speed ?? speed,
|
|
28
|
+
response_format: 'mp3',
|
|
29
|
+
};
|
|
30
|
+
if (instructions)
|
|
31
|
+
params.instructions = instructions;
|
|
32
|
+
const response = await openai.audio.speech.create(params);
|
|
33
|
+
const data = Buffer.from(await response.arrayBuffer());
|
|
34
|
+
return {
|
|
35
|
+
data,
|
|
36
|
+
durationMs: 0,
|
|
37
|
+
format: { sampleRate: 24000, channels: 1, codec: 'mp3' },
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
estimateDurationMs(text, options) {
|
|
41
|
+
const spd = options?.speed ?? speed;
|
|
42
|
+
const words = text.split(/\s+/).length;
|
|
43
|
+
return (words / (150 * spd)) * 60_000;
|
|
44
|
+
},
|
|
45
|
+
async isAvailable() {
|
|
46
|
+
return !!apiKey;
|
|
47
|
+
},
|
|
48
|
+
async dispose() {
|
|
49
|
+
client = null;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/voiceover/providers/openai.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,SAA+B,EAAE;IAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAA;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,iBAAiB,CAAA;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,GAAG,CAAA;IACjC,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAA;IAExC,IAAI,MAAM,GAAwB,IAAI,CAAA;IAEtC,KAAK,UAAU,SAAS;QACtB,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QACzB,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAA;QAC/C,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAA4B,CAAA;QAC1D,OAAO,MAAM,CAAA;IACf,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ;QAEd,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,OAAoB;YACjD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,MAAM,MAAM,GAA4B;gBACtC,KAAK;gBACL,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK;gBAC9B,KAAK,EAAE,IAAI;gBACX,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK;gBAC9B,eAAe,EAAE,KAAK;aACvB,CAAA;YACD,IAAI,YAAY;gBAAE,MAAM,CAAC,YAAY,GAAG,YAAY,CAAA;YAEpD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACzD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;YAEtD,OAAO;gBACL,IAAI;gBACJ,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;aACzD,CAAA;QACH,CAAC;QAED,kBAAkB,CAAC,IAAY,EAAE,OAAoB;YACnD,MAAM,GAAG,GAAG,OAAO,EAAE,KAAK,IAAI,KAAK,CAAA;YACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;YACtC,OAAO,CAAC,KAAK,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,MAAM,CAAA;QACvC,CAAC;QAED,KAAK,CAAC,WAAW;YACf,OAAO,CAAC,CAAC,MAAM,CAAA;QACjB,CAAC;QAED,KAAK,CAAC,OAAO;YACX,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SubtitledTrace } from '../types/subtitle';
|
|
2
|
+
import type { TtsProvider, VoiceoveredTrace } from '../types/voiceover';
|
|
3
|
+
/**
|
|
4
|
+
* Generate voiceover audio from subtitles using a TTS provider.
|
|
5
|
+
* Produces individual audio segments, pads with silence to match timing,
|
|
6
|
+
* and concatenates into a single audio track.
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateVoiceover(trace: SubtitledTrace, provider: TtsProvider, tmpDir: string): Promise<VoiceoveredTrace>;
|
|
9
|
+
//# sourceMappingURL=voiceover-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceover-processor.d.ts","sourceRoot":"","sources":["../../src/voiceover/voiceover-processor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAkB,MAAM,oBAAoB,CAAA;AAuBvF;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAuE3B"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
function getAudioDurationMs(filePath) {
|
|
5
|
+
const output = execFileSync('ffprobe', [
|
|
6
|
+
'-v', 'quiet',
|
|
7
|
+
'-show_entries', 'format=duration',
|
|
8
|
+
'-of', 'csv=p=0',
|
|
9
|
+
filePath,
|
|
10
|
+
]).toString().trim();
|
|
11
|
+
return Math.round(Number(output) * 1000);
|
|
12
|
+
}
|
|
13
|
+
function generateSilence(durationMs, outputPath, sampleRate = 24000) {
|
|
14
|
+
const durationSec = Math.max(0.01, durationMs / 1000);
|
|
15
|
+
execFileSync('ffmpeg', [
|
|
16
|
+
'-y', '-f', 'lavfi',
|
|
17
|
+
'-i', `anullsrc=r=${sampleRate}:cl=mono`,
|
|
18
|
+
'-t', String(durationSec),
|
|
19
|
+
'-c:a', 'libmp3lame', '-q:a', '9',
|
|
20
|
+
outputPath,
|
|
21
|
+
], { stdio: 'pipe' });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate voiceover audio from subtitles using a TTS provider.
|
|
25
|
+
* Produces individual audio segments, pads with silence to match timing,
|
|
26
|
+
* and concatenates into a single audio track.
|
|
27
|
+
*/
|
|
28
|
+
export async function generateVoiceover(trace, provider, tmpDir) {
|
|
29
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
30
|
+
const entries = [];
|
|
31
|
+
const segmentFiles = [];
|
|
32
|
+
let cursor = 0;
|
|
33
|
+
for (const subtitle of trace.subtitles) {
|
|
34
|
+
// Insert silence for gap before this segment
|
|
35
|
+
if (subtitle.startMs > cursor) {
|
|
36
|
+
const silencePath = path.join(tmpDir, `silence-${subtitle.index}.mp3`);
|
|
37
|
+
generateSilence(subtitle.startMs - cursor, silencePath);
|
|
38
|
+
segmentFiles.push(silencePath);
|
|
39
|
+
}
|
|
40
|
+
// Generate TTS
|
|
41
|
+
const segPath = path.join(tmpDir, `seg-${subtitle.index}.mp3`);
|
|
42
|
+
const audio = await provider.synthesize(subtitle.text);
|
|
43
|
+
fs.writeFileSync(segPath, audio.data);
|
|
44
|
+
const audioDuration = getAudioDurationMs(segPath);
|
|
45
|
+
const windowDuration = subtitle.endMs - subtitle.startMs;
|
|
46
|
+
if (audioDuration < windowDuration) {
|
|
47
|
+
segmentFiles.push(segPath);
|
|
48
|
+
const padPath = path.join(tmpDir, `pad-${subtitle.index}.mp3`);
|
|
49
|
+
generateSilence(windowDuration - audioDuration, padPath);
|
|
50
|
+
segmentFiles.push(padPath);
|
|
51
|
+
cursor = subtitle.endMs;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
segmentFiles.push(segPath);
|
|
55
|
+
cursor = subtitle.startMs + audioDuration;
|
|
56
|
+
}
|
|
57
|
+
entries.push({
|
|
58
|
+
subtitle,
|
|
59
|
+
audio,
|
|
60
|
+
outputStartMs: subtitle.startMs,
|
|
61
|
+
outputEndMs: Math.max(subtitle.endMs, subtitle.startMs + audioDuration),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Concat all segments into single audio track
|
|
65
|
+
const concatList = path.join(tmpDir, 'concat.txt');
|
|
66
|
+
fs.writeFileSync(concatList, segmentFiles.map((f) => `file '${f}'`).join('\n'));
|
|
67
|
+
const audioTrackPath = path.join(tmpDir, 'voiceover.mp3');
|
|
68
|
+
if (segmentFiles.length > 0) {
|
|
69
|
+
execFileSync('ffmpeg', [
|
|
70
|
+
'-y', '-f', 'concat', '-safe', '0',
|
|
71
|
+
'-i', concatList,
|
|
72
|
+
'-c:a', 'libmp3lame', '-q:a', '2',
|
|
73
|
+
audioTrackPath,
|
|
74
|
+
], { stdio: 'pipe' });
|
|
75
|
+
}
|
|
76
|
+
const totalDurationMs = segmentFiles.length > 0
|
|
77
|
+
? getAudioDurationMs(audioTrackPath)
|
|
78
|
+
: 0;
|
|
79
|
+
return {
|
|
80
|
+
...trace,
|
|
81
|
+
voiceover: {
|
|
82
|
+
entries,
|
|
83
|
+
audioTrackPath,
|
|
84
|
+
totalDurationMs,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=voiceover-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voiceover-processor.js","sourceRoot":"","sources":["../../src/voiceover/voiceover-processor.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "playwright-recast",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Fluent pipeline library for processing Playwright traces into polished demo videos — TTS voiceover, subtitles, speed control, and zoom.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Patrik Szewczyk <Patrik.Szewczyk@gmail.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/ThePatriczek/playwright-recast.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/ThePatriczek/playwright-recast",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"playwright",
|
|
15
|
+
"trace",
|
|
16
|
+
"video",
|
|
17
|
+
"demo",
|
|
18
|
+
"tts",
|
|
19
|
+
"voiceover",
|
|
20
|
+
"subtitles",
|
|
21
|
+
"srt",
|
|
22
|
+
"bdd",
|
|
23
|
+
"automation"
|
|
24
|
+
],
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"bin": {
|
|
28
|
+
"playwright-recast": "./dist/cli.js"
|
|
29
|
+
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./helpers": {
|
|
36
|
+
"types": "./dist/helpers.d.ts",
|
|
37
|
+
"default": "./dist/helpers.js"
|
|
38
|
+
},
|
|
39
|
+
"./providers/openai": {
|
|
40
|
+
"types": "./dist/voiceover/providers/openai.d.ts",
|
|
41
|
+
"default": "./dist/voiceover/providers/openai.js"
|
|
42
|
+
},
|
|
43
|
+
"./providers/elevenlabs": {
|
|
44
|
+
"types": "./dist/voiceover/providers/elevenlabs.d.ts",
|
|
45
|
+
"default": "./dist/voiceover/providers/elevenlabs.js"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"test:watch": "vitest watch",
|
|
57
|
+
"typecheck": "tsc --noEmit",
|
|
58
|
+
"prepublishOnly": "npm run build"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"fflate": "^0.8.2"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@playwright/test": ">=1.40.0",
|
|
65
|
+
"openai": ">=5.0.0",
|
|
66
|
+
"@elevenlabs/elevenlabs-js": ">=2.0.0"
|
|
67
|
+
},
|
|
68
|
+
"peerDependenciesMeta": {
|
|
69
|
+
"@playwright/test": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"openai": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"@elevenlabs/elevenlabs-js": {
|
|
76
|
+
"optional": true
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@elevenlabs/elevenlabs-js": "^2.40.0",
|
|
81
|
+
"@playwright/test": "^1.58.0",
|
|
82
|
+
"@types/node": "^22.0.0",
|
|
83
|
+
"openai": "^6.32.0",
|
|
84
|
+
"typescript": "^5.9.0",
|
|
85
|
+
"vitest": "^4.0.0"
|
|
86
|
+
}
|
|
87
|
+
}
|