recordable 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 +303 -0
- package/dist/actions.d.ts +140 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +184 -0
- package/dist/actions.js.map +1 -0
- package/dist/audio/track.d.ts +45 -0
- package/dist/audio/track.d.ts.map +1 -0
- package/dist/audio/track.js +61 -0
- package/dist/audio/track.js.map +1 -0
- package/dist/browser/cursor.d.ts +33 -0
- package/dist/browser/cursor.d.ts.map +1 -0
- package/dist/browser/cursor.js +118 -0
- package/dist/browser/cursor.js.map +1 -0
- package/dist/browser/dom.d.ts +31 -0
- package/dist/browser/dom.d.ts.map +1 -0
- package/dist/browser/dom.js +134 -0
- package/dist/browser/dom.js.map +1 -0
- package/dist/browser/play-button.d.ts +11 -0
- package/dist/browser/play-button.d.ts.map +1 -0
- package/dist/browser/play-button.js +87 -0
- package/dist/browser/play-button.js.map +1 -0
- package/dist/browser/runtime.d.ts +66 -0
- package/dist/browser/runtime.d.ts.map +1 -0
- package/dist/browser/runtime.js +271 -0
- package/dist/browser/runtime.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/compose/mix.d.ts +13 -0
- package/dist/compose/mix.d.ts.map +1 -0
- package/dist/compose/mix.js +50 -0
- package/dist/compose/mix.js.map +1 -0
- package/dist/compose/recordable.d.ts +149 -0
- package/dist/compose/recordable.d.ts.map +1 -0
- package/dist/compose/recordable.js +337 -0
- package/dist/compose/recordable.js.map +1 -0
- package/dist/compose/session.d.ts +38 -0
- package/dist/compose/session.d.ts.map +1 -0
- package/dist/compose/session.js +122 -0
- package/dist/compose/session.js.map +1 -0
- package/dist/config.d.ts +93 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/ffmpeg.d.ts +8 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +55 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/formats/json.d.ts +12 -0
- package/dist/formats/json.d.ts.map +1 -0
- package/dist/formats/json.js +20 -0
- package/dist/formats/json.js.map +1 -0
- package/dist/formats/markdown/method.d.ts +25 -0
- package/dist/formats/markdown/method.d.ts.map +1 -0
- package/dist/formats/markdown/method.js +48 -0
- package/dist/formats/markdown/method.js.map +1 -0
- package/dist/formats/markdown/parse.d.ts +44 -0
- package/dist/formats/markdown/parse.d.ts.map +1 -0
- package/dist/formats/markdown/parse.js +143 -0
- package/dist/formats/markdown/parse.js.map +1 -0
- package/dist/fs.d.ts +9 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +30 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +21 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +45 -0
- package/dist/logger.js.map +1 -0
- package/dist/schema.d.ts +5 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +100 -0
- package/dist/schema.js.map +1 -0
- package/dist/script.d.ts +21 -0
- package/dist/script.d.ts.map +1 -0
- package/dist/script.js +26 -0
- package/dist/script.js.map +1 -0
- package/dist/targets.d.ts +6 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +13 -0
- package/dist/targets.js.map +1 -0
- package/dist/timing.d.ts +41 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +149 -0
- package/dist/timing.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +8 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +54 -0
- package/dist/validate.js.map +1 -0
- package/dist/video/recorder.d.ts +57 -0
- package/dist/video/recorder.d.ts.map +1 -0
- package/dist/video/recorder.js +238 -0
- package/dist/video/recorder.js.map +1 -0
- package/dist/video/stitch.d.ts +15 -0
- package/dist/video/stitch.d.ts.map +1 -0
- package/dist/video/stitch.js +111 -0
- package/dist/video/stitch.js.map +1 -0
- package/dist/voiceover/alignment.d.ts +14 -0
- package/dist/voiceover/alignment.d.ts.map +1 -0
- package/dist/voiceover/alignment.js +13 -0
- package/dist/voiceover/alignment.js.map +1 -0
- package/dist/voiceover/cache.d.ts +22 -0
- package/dist/voiceover/cache.d.ts.map +1 -0
- package/dist/voiceover/cache.js +55 -0
- package/dist/voiceover/cache.js.map +1 -0
- package/dist/voiceover/compile.d.ts +35 -0
- package/dist/voiceover/compile.d.ts.map +1 -0
- package/dist/voiceover/compile.js +194 -0
- package/dist/voiceover/compile.js.map +1 -0
- package/dist/voiceover/elevenlabs.d.ts +16 -0
- package/dist/voiceover/elevenlabs.d.ts.map +1 -0
- package/dist/voiceover/elevenlabs.js +66 -0
- package/dist/voiceover/elevenlabs.js.map +1 -0
- package/dist/voiceover/index.d.ts +7 -0
- package/dist/voiceover/index.d.ts.map +1 -0
- package/dist/voiceover/index.js +8 -0
- package/dist/voiceover/index.js.map +1 -0
- package/dist/voiceover/mock.d.ts +15 -0
- package/dist/voiceover/mock.d.ts.map +1 -0
- package/dist/voiceover/mock.js +41 -0
- package/dist/voiceover/mock.js.map +1 -0
- package/dist/voiceover/types.d.ts +31 -0
- package/dist/voiceover/types.d.ts.map +1 -0
- package/dist/voiceover/types.js +10 -0
- package/dist/voiceover/types.js.map +1 -0
- package/package.json +86 -0
- package/recordable.schema.json +738 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/browser/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { sleep, truncate } from "../utils.js";
|
|
2
|
+
import { resolveTarget } from "../targets.js";
|
|
3
|
+
import { getElementCenter, originToCoords, scrollIntoView, smoothScrollToTarget, } from "./dom.js";
|
|
4
|
+
import { Cursor } from "./cursor.js";
|
|
5
|
+
import { jitter, typingDuration, typingGaps, NAV_PROBE_MS, PRE_CLICK_MS, } from "../timing.js";
|
|
6
|
+
import { playButtonScript, PLAY_BINDING, PLAY_BUTTON_ID, } from "./play-button.js";
|
|
7
|
+
// ─── Compose layer: the runtime ──────────────────────────────────────────────
|
|
8
|
+
//
|
|
9
|
+
// *How* each action is performed on a live page — clicks, typing, scrolling,
|
|
10
|
+
// zooming, the cursor overlay, the resume gate. It owns the cursor and the zoom
|
|
11
|
+
// transform state (both per-page concerns); the builder enqueues calls to these
|
|
12
|
+
// methods, and the session drives them. No queue, no recorder, no recording flag
|
|
13
|
+
// here — purely page interaction.
|
|
14
|
+
export class Runtime {
|
|
15
|
+
getCfg;
|
|
16
|
+
log;
|
|
17
|
+
cursor = new Cursor();
|
|
18
|
+
zoom = { tx: 0, ty: 0, s: 1 };
|
|
19
|
+
// Play-button bridge state (the resume gate).
|
|
20
|
+
playResolver = null;
|
|
21
|
+
playBindingExposed = false;
|
|
22
|
+
constructor(getCfg, log) {
|
|
23
|
+
this.getCfg = getCfg;
|
|
24
|
+
this.log = log;
|
|
25
|
+
}
|
|
26
|
+
/** The current zoom transform — the session re-reads it when re-injecting the
|
|
27
|
+
* cursor overlay across navigations. */
|
|
28
|
+
get zoomState() {
|
|
29
|
+
return this.zoom;
|
|
30
|
+
}
|
|
31
|
+
/** Drop any zoom transform (a fresh document carries none). */
|
|
32
|
+
resetZoomState() {
|
|
33
|
+
this.zoom = { tx: 0, ty: 0, s: 1 };
|
|
34
|
+
}
|
|
35
|
+
/** (Re-)inject the cursor overlay at the carried position, if enabled. */
|
|
36
|
+
async injectCursor(page) {
|
|
37
|
+
if (this.getCfg().cursor)
|
|
38
|
+
await this.cursor.inject(page, this.zoom);
|
|
39
|
+
}
|
|
40
|
+
// ─── Navigation ────────────────────────────────────────────────────────────
|
|
41
|
+
async visit(page, url, options) {
|
|
42
|
+
this.log("Visit", url);
|
|
43
|
+
await page.goto(url, {
|
|
44
|
+
waitUntil: "networkidle2",
|
|
45
|
+
timeout: this.getCfg().visitTimeout,
|
|
46
|
+
...options,
|
|
47
|
+
});
|
|
48
|
+
// A fresh document carries no zoom transform — drop any stale state so the
|
|
49
|
+
// overlay (and later moves) position against the new page's viewport.
|
|
50
|
+
this.resetZoomState();
|
|
51
|
+
await this.injectCursor(page);
|
|
52
|
+
}
|
|
53
|
+
async waitFor(page, target, options = {}) {
|
|
54
|
+
const { state = "visible", timeout = this.getCfg().visitTimeout } = options;
|
|
55
|
+
this.log("WaitFor", `${target} (${state})`);
|
|
56
|
+
await page.waitForSelector(resolveTarget(target), {
|
|
57
|
+
timeout,
|
|
58
|
+
visible: state === "visible",
|
|
59
|
+
hidden: state === "hidden",
|
|
60
|
+
});
|
|
61
|
+
await this.injectCursor(page);
|
|
62
|
+
}
|
|
63
|
+
// ─── Interactions ──────────────────────────────────────────────────────────
|
|
64
|
+
async click(page, target) {
|
|
65
|
+
this.log("Click", target);
|
|
66
|
+
await this._click(page, target);
|
|
67
|
+
}
|
|
68
|
+
async hover(page, target) {
|
|
69
|
+
this.log("Hover", target);
|
|
70
|
+
if (this.getCfg().autoScroll)
|
|
71
|
+
await this._scrollIntoView(page, target);
|
|
72
|
+
const { x, y } = await getElementCenter(page, target);
|
|
73
|
+
await this._moveTo(page, x, y);
|
|
74
|
+
}
|
|
75
|
+
async type(page, target, text, options = {}) {
|
|
76
|
+
this.log("Type", `${target} "${truncate(text)}"`);
|
|
77
|
+
await this._click(page, target);
|
|
78
|
+
const total = options.duration ?? typingDuration(text, this.getCfg().typingSpeed);
|
|
79
|
+
const gaps = typingGaps(text, this.getCfg().typingSpeed, total);
|
|
80
|
+
if (gaps.length === 0)
|
|
81
|
+
return;
|
|
82
|
+
await sleep(gaps[0]); // lead beat before the first keystroke
|
|
83
|
+
let i = 1;
|
|
84
|
+
for (const char of text) {
|
|
85
|
+
await page.keyboard.type(char);
|
|
86
|
+
await sleep(gaps[i++] ?? 0);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async clear(page, target) {
|
|
90
|
+
this.log("Clear", target);
|
|
91
|
+
await this._click(page, target);
|
|
92
|
+
const mod = process.platform === "darwin" ? "Meta" : "Control";
|
|
93
|
+
await page.keyboard.down(mod);
|
|
94
|
+
await page.keyboard.press("KeyA");
|
|
95
|
+
await page.keyboard.up(mod);
|
|
96
|
+
await page.keyboard.press("Backspace");
|
|
97
|
+
}
|
|
98
|
+
async select(page, target, value) {
|
|
99
|
+
this.log("Select", `${target} ${value}`);
|
|
100
|
+
if (this.getCfg().autoScroll)
|
|
101
|
+
await this._scrollIntoView(page, target);
|
|
102
|
+
const { x, y } = await getElementCenter(page, target);
|
|
103
|
+
if (this.getCfg().cursor) {
|
|
104
|
+
await this.cursor.moveTo(page, x, y, this.zoom);
|
|
105
|
+
await sleep(jitter(PRE_CLICK_MS));
|
|
106
|
+
await this.cursor.clickEffect(page);
|
|
107
|
+
}
|
|
108
|
+
await page.select(target, value);
|
|
109
|
+
}
|
|
110
|
+
async key(page, key) {
|
|
111
|
+
this.log("Key", key);
|
|
112
|
+
await page.keyboard.press(key);
|
|
113
|
+
}
|
|
114
|
+
async mouse(page, target) {
|
|
115
|
+
const { x, y } = typeof target === "string"
|
|
116
|
+
? await getElementCenter(page, target)
|
|
117
|
+
: target;
|
|
118
|
+
this.log("Mouse", typeof target === "string" ? target : `(${x}, ${y})`);
|
|
119
|
+
await this._moveTo(page, x, y);
|
|
120
|
+
}
|
|
121
|
+
// ─── Scrolling ─────────────────────────────────────────────────────────────
|
|
122
|
+
async scroll(page, target, options = {}) {
|
|
123
|
+
this.log("Scroll", String(target));
|
|
124
|
+
await smoothScrollToTarget(page, target, options.duration ?? this.getCfg().scrollDuration);
|
|
125
|
+
}
|
|
126
|
+
// ─── Zoom ──────────────────────────────────────────────────────────────────
|
|
127
|
+
async zoomTo(page, level, options = {}) {
|
|
128
|
+
const { origin = "center", duration } = options;
|
|
129
|
+
this.log("Zoom", `${level}x ${origin}`);
|
|
130
|
+
const dur = duration ?? this.getCfg().zoomDuration;
|
|
131
|
+
const { x, y } = await originToCoords(page, origin);
|
|
132
|
+
// Express zoom as translate()+scale() on a 0,0 origin so that a single CSS
|
|
133
|
+
// `transform` transition smoothly animates both level and origin.
|
|
134
|
+
const tx = x * (1 - level);
|
|
135
|
+
const ty = y * (1 - level);
|
|
136
|
+
this.zoom = { tx, ty, s: level };
|
|
137
|
+
await page.evaluate(({ tx, ty, level, dur }) => new Promise((resolve) => {
|
|
138
|
+
const root = document.documentElement;
|
|
139
|
+
root.style.transformOrigin = "0 0";
|
|
140
|
+
root.style.transition = `transform ${dur}ms ease-in-out`;
|
|
141
|
+
root.style.transform = `translate(${tx}px, ${ty}px) scale(${level})`;
|
|
142
|
+
setTimeout(resolve, dur + 50);
|
|
143
|
+
}), { tx, ty, level, dur });
|
|
144
|
+
}
|
|
145
|
+
async resetZoom(page, options = {}) {
|
|
146
|
+
this.log("Zoom", "reset");
|
|
147
|
+
this.resetZoomState();
|
|
148
|
+
const dur = options.duration ?? this.getCfg().zoomDuration;
|
|
149
|
+
await page.evaluate((dur) => new Promise((resolve) => {
|
|
150
|
+
const root = document.documentElement;
|
|
151
|
+
root.style.transition = `transform ${dur}ms ease-in-out`;
|
|
152
|
+
root.style.transform = "none";
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
root.style.transition = "";
|
|
155
|
+
root.style.transformOrigin = "";
|
|
156
|
+
resolve();
|
|
157
|
+
}, dur + 50);
|
|
158
|
+
}), dur);
|
|
159
|
+
}
|
|
160
|
+
// ─── Private interaction helpers ─────────────────────────────────────────────
|
|
161
|
+
/** Click a target's centre. Uses page.mouse.click() not ElementHandle.click()
|
|
162
|
+
* to avoid Puppeteer's built-in scrollIntoView overriding our centred scroll. */
|
|
163
|
+
async _click(page, target) {
|
|
164
|
+
if (this.getCfg().autoScroll)
|
|
165
|
+
await this._scrollIntoView(page, target);
|
|
166
|
+
const { x, y } = await getElementCenter(page, target);
|
|
167
|
+
if (this.getCfg().cursor) {
|
|
168
|
+
await this.cursor.moveTo(page, x, y, this.zoom);
|
|
169
|
+
await sleep(jitter(PRE_CLICK_MS));
|
|
170
|
+
await this.cursor.clickEffect(page);
|
|
171
|
+
}
|
|
172
|
+
await this._clickPoint(page, x, y);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Click at viewport coords and, if the click triggers a navigation, wait for the
|
|
176
|
+
* new page to settle before returning — so a navigating `click()` behaves like a
|
|
177
|
+
* `visit()` and the next action lands on the loaded page rather than racing it.
|
|
178
|
+
* In-page clicks pay only a short probe.
|
|
179
|
+
*/
|
|
180
|
+
async _clickPoint(page, x, y) {
|
|
181
|
+
let navStarted = false;
|
|
182
|
+
const onNav = (frame) => {
|
|
183
|
+
if (frame === page.mainFrame())
|
|
184
|
+
navStarted = true;
|
|
185
|
+
};
|
|
186
|
+
page.on("framenavigated", onNav);
|
|
187
|
+
try {
|
|
188
|
+
await page.mouse.click(x, y);
|
|
189
|
+
// Give a navigation a brief moment to commit; most clicks don't navigate,
|
|
190
|
+
// so we can't block on a full navigation wait unconditionally.
|
|
191
|
+
await sleep(NAV_PROBE_MS);
|
|
192
|
+
if (navStarted) {
|
|
193
|
+
await page
|
|
194
|
+
.waitForNetworkIdle({
|
|
195
|
+
idleTime: 500,
|
|
196
|
+
timeout: this.getCfg().visitTimeout,
|
|
197
|
+
})
|
|
198
|
+
.catch(() => { });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
page.off("framenavigated", onNav);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** Move to viewport coords, animating the overlay when the cursor is enabled. */
|
|
206
|
+
async _moveTo(page, x, y) {
|
|
207
|
+
if (this.getCfg().cursor)
|
|
208
|
+
await this.cursor.moveTo(page, x, y, this.zoom);
|
|
209
|
+
else
|
|
210
|
+
await page.mouse.move(x, y);
|
|
211
|
+
}
|
|
212
|
+
/** Scroll a target into view using the configured margin/speed. */
|
|
213
|
+
_scrollIntoView(page, target) {
|
|
214
|
+
const cfg = this.getCfg();
|
|
215
|
+
return scrollIntoView(page, target, cfg.scrollMargin, cfg.scrollSpeed);
|
|
216
|
+
}
|
|
217
|
+
// ─── Resume gate (▶ Play button) ─────────────────────────────────────────────
|
|
218
|
+
/**
|
|
219
|
+
* Block until the user resumes — by clicking the in-page ▶ Play button, or by
|
|
220
|
+
* pressing Enter in the *terminal*. The in-page button is click-only so the live
|
|
221
|
+
* page keeps its own keyboard (Enter to submit a form, etc.); the terminal
|
|
222
|
+
* fallback means a resume is still reachable if the button fails to render.
|
|
223
|
+
*/
|
|
224
|
+
async waitForPlay(page, message) {
|
|
225
|
+
let settle;
|
|
226
|
+
const played = new Promise((resolve) => (settle = resolve));
|
|
227
|
+
// Bridge page → Node: the button's click handler calls window[PLAY_BINDING],
|
|
228
|
+
// which fires this exposed function. Exposed functions survive navigations, so
|
|
229
|
+
// expose once and reuse across calls.
|
|
230
|
+
this.playResolver = settle;
|
|
231
|
+
if (!this.playBindingExposed) {
|
|
232
|
+
await page.exposeFunction(PLAY_BINDING, () => this.playResolver?.());
|
|
233
|
+
this.playBindingExposed = true;
|
|
234
|
+
}
|
|
235
|
+
// Terminal fallback: resume on Enter from stdin (TTY only). Works even if the
|
|
236
|
+
// in-page button never renders.
|
|
237
|
+
const stdin = process.stdin;
|
|
238
|
+
const onStdin = (chunk) => {
|
|
239
|
+
if (chunk.includes(0x0a) || chunk.includes(0x0d))
|
|
240
|
+
settle();
|
|
241
|
+
};
|
|
242
|
+
const stdinFallback = Boolean(stdin.isTTY);
|
|
243
|
+
if (stdinFallback) {
|
|
244
|
+
stdin.resume();
|
|
245
|
+
stdin.on("data", onStdin);
|
|
246
|
+
}
|
|
247
|
+
// Inject the button now, and on every future document so it survives the
|
|
248
|
+
// navigations of a login flow. A failure here is non-fatal — the terminal
|
|
249
|
+
// fallback still resumes — but surface it so a broken button is visible.
|
|
250
|
+
const script = playButtonScript(message, PLAY_BUTTON_ID, PLAY_BINDING);
|
|
251
|
+
const { identifier } = await page.evaluateOnNewDocument(script);
|
|
252
|
+
await page
|
|
253
|
+
.evaluate(script)
|
|
254
|
+
.catch((e) => this.log.warn(`could not inject ▶ Play button: ${String(e)}`));
|
|
255
|
+
this.log("Resume", stdinFallback
|
|
256
|
+
? "waiting for ▶ Play (or press Enter here)…"
|
|
257
|
+
: "waiting for ▶ Play…");
|
|
258
|
+
await played;
|
|
259
|
+
// Clean up: stop the stdin listener, stop re-injecting, remove the button.
|
|
260
|
+
this.playResolver = null;
|
|
261
|
+
if (stdinFallback) {
|
|
262
|
+
stdin.off("data", onStdin);
|
|
263
|
+
stdin.pause();
|
|
264
|
+
}
|
|
265
|
+
await page.removeScriptToEvaluateOnNewDocument(identifier).catch(() => { });
|
|
266
|
+
await page
|
|
267
|
+
.evaluate((id) => document.getElementById(id)?.remove(), PLAY_BUTTON_ID)
|
|
268
|
+
.catch(() => { });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/browser/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve, basename, dirname } from "node:path";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { Recordable } from "./index.js";
|
|
6
|
+
import { createLogger } from "./logger.js";
|
|
7
|
+
import { isRecordableError } from "./errors.js";
|
|
8
|
+
// CLI-level messages always print (the recorder's own `silent` governs run output).
|
|
9
|
+
const log = createLogger(() => false);
|
|
10
|
+
// ─── recordable CLI ──────────────────────────────────────────────────────────
|
|
11
|
+
//
|
|
12
|
+
// recordable <script.json | script.md> [options]
|
|
13
|
+
//
|
|
14
|
+
// A thin wrapper over the programmatic API: read the file, then
|
|
15
|
+
// `new Recordable({ baseDir, ...flags }).fromJSON|fromMarkdown(contents).run()`.
|
|
16
|
+
// Dispatches by extension; `baseDir` (the script's folder) handles relative path
|
|
17
|
+
// resolution, the sibling `.env`, and assets/output defaults. Designed for
|
|
18
|
+
// `npx recordable demo.md`.
|
|
19
|
+
const USAGE = `recordable — record a declarative script
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
recordable <script.json | script.md> [options]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--check Validate the script and exit (no browser, no audio, no recording)
|
|
26
|
+
--headless Run without a visible browser window
|
|
27
|
+
--silent Suppress recorder console output
|
|
28
|
+
--out-dir <dir> Output directory (overrides the script's config)
|
|
29
|
+
--name <name> Output filename (without extension)
|
|
30
|
+
--no-timestamp Don't prepend an ISO timestamp to the filename
|
|
31
|
+
-h, --help Show this help
|
|
32
|
+
|
|
33
|
+
A .json script is an array of { "action", ... } actions, or { "config", "actions" }.
|
|
34
|
+
A .md file authors the same actions as markers in prose; with a "voiceover"
|
|
35
|
+
frontmatter block it generates narration audio (needs ELEVENLABS_API_KEY, loaded
|
|
36
|
+
from a .env beside the file) into a sibling assets/ folder. Provider/voice/model
|
|
37
|
+
default from RECORDABLE_TTS_PROVIDER / RECORDABLE_VOICE_ID / RECORDABLE_MODEL_ID,
|
|
38
|
+
which the frontmatter overrides. Config precedence: defaults < file < flags.
|
|
39
|
+
|
|
40
|
+
Relative "visit" URLs (e.g. "./index.html") and a relative "outputDir" resolve
|
|
41
|
+
against the script file, so a script and its output stay together. --out-dir
|
|
42
|
+
overrides (relative to the current directory).`;
|
|
43
|
+
/** Parse argv with Node's built-in parser — strict, so bad flags throw. */
|
|
44
|
+
function parseCliArgs(argv) {
|
|
45
|
+
const { values, positionals } = (() => {
|
|
46
|
+
try {
|
|
47
|
+
return parseArgs({
|
|
48
|
+
args: argv,
|
|
49
|
+
allowPositionals: true,
|
|
50
|
+
options: {
|
|
51
|
+
check: { type: "boolean" },
|
|
52
|
+
headless: { type: "boolean" },
|
|
53
|
+
silent: { type: "boolean" },
|
|
54
|
+
"no-timestamp": { type: "boolean" },
|
|
55
|
+
"out-dir": { type: "string" },
|
|
56
|
+
name: { type: "string" },
|
|
57
|
+
help: { type: "boolean", short: "h" },
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
fail(err.message);
|
|
63
|
+
}
|
|
64
|
+
})();
|
|
65
|
+
if (values.help) {
|
|
66
|
+
console.log(USAGE);
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
if (positionals.length > 1)
|
|
70
|
+
fail(`unexpected extra argument: ${positionals[1]}`);
|
|
71
|
+
const config = {};
|
|
72
|
+
if (values.headless)
|
|
73
|
+
config.headless = true;
|
|
74
|
+
if (values.silent)
|
|
75
|
+
config.silent = true;
|
|
76
|
+
if (values["no-timestamp"])
|
|
77
|
+
config.outputTimestamp = false;
|
|
78
|
+
// Resolve --out-dir against cwd now so baseDir resolution leaves it alone.
|
|
79
|
+
if (values["out-dir"])
|
|
80
|
+
config.outputDir = resolve(values["out-dir"]);
|
|
81
|
+
if (values.name)
|
|
82
|
+
config.outputName = values.name;
|
|
83
|
+
return { file: positionals[0], check: Boolean(values.check), config };
|
|
84
|
+
}
|
|
85
|
+
function fail(message) {
|
|
86
|
+
log.error(message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
async function main() {
|
|
90
|
+
const args = parseCliArgs(process.argv.slice(2));
|
|
91
|
+
if (!args.file)
|
|
92
|
+
fail("no script file given (try --help)");
|
|
93
|
+
const file = resolve(args.file);
|
|
94
|
+
const isMarkdown = /\.(md|markdown)$/i.test(file);
|
|
95
|
+
// baseDir = the script's folder: resolves its relative paths, loads a sibling
|
|
96
|
+
// .env, and defaults assets/output to <baseDir>/assets and <baseDir>/output.
|
|
97
|
+
const config = { baseDir: dirname(file), ...args.config };
|
|
98
|
+
let contents;
|
|
99
|
+
try {
|
|
100
|
+
contents = readFileSync(file, "utf8");
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
fail(`${basename(file)}: file not found`);
|
|
104
|
+
}
|
|
105
|
+
// Build the recording — same call a script makes. This parses + validates
|
|
106
|
+
// (bad actions/keys throw) but never launches a browser or synthesizes audio;
|
|
107
|
+
// that all happens in run(), so --check can build and stop here.
|
|
108
|
+
let rec;
|
|
109
|
+
try {
|
|
110
|
+
rec = isMarkdown
|
|
111
|
+
? new Recordable(config).fromMarkdown(contents)
|
|
112
|
+
: new Recordable(config).fromJSON(contents);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
fail(`${basename(file)}: ${err.message}`);
|
|
116
|
+
}
|
|
117
|
+
if (args.check) {
|
|
118
|
+
log("OK", `${basename(file)} is valid`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
await rec.run();
|
|
122
|
+
}
|
|
123
|
+
main().catch((err) => {
|
|
124
|
+
// Expected failures (bad config, missing file, ffmpeg/TTS/browser) print a
|
|
125
|
+
// clean line; anything else is a bug, so keep its stack for debugging.
|
|
126
|
+
if (isRecordableError(err))
|
|
127
|
+
fail(err.message);
|
|
128
|
+
log.error(String(err?.stack ?? err));
|
|
129
|
+
process.exit(1);
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,oFAAoF;AACpF,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AAEtC,gFAAgF;AAChF,EAAE;AACF,mDAAmD;AACnD,EAAE;AACF,gEAAgE;AAChE,iFAAiF;AACjF,iFAAiF;AACjF,2EAA2E;AAC3E,4BAA4B;AAE5B,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;+CAuBiC,CAAC;AAQhD,2EAA2E;AAC3E,SAAS,YAAY,CAAC,IAAc;IAClC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,GAAG,EAAE;QACpC,IAAI,CAAC;YACH,OAAO,SAAS,CAAC;gBACf,IAAI,EAAE,IAAI;gBACV,gBAAgB,EAAE,IAAI;gBACtB,OAAO,EAAE;oBACP,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBAC1B,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBAC3B,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBACnC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC7B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACxB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;iBACtC;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QACxB,IAAI,CAAC,8BAA8B,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEvD,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,IAAI,MAAM,CAAC,QAAQ;QAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC5C,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;IACxC,IAAI,MAAM,CAAC,cAAc,CAAC;QAAE,MAAM,CAAC,eAAe,GAAG,KAAK,CAAC;IAC3D,2EAA2E;IAC3E,IAAI,MAAM,CAAC,SAAS,CAAC;QAAE,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACrE,IAAI,MAAM,CAAC,IAAI;QAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAEjD,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,IAAI,CAAC,OAAe;IAC3B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAE1D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,8EAA8E;IAC9E,6EAA6E;IAC7E,MAAM,MAAM,GAAqB,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAE5E,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC5C,CAAC;IAED,0EAA0E;IAC1E,8EAA8E;IAC9E,iEAAiE;IACjE,IAAI,GAAe,CAAC;IACpB,IAAI,CAAC;QACH,GAAG,GAAG,UAAU;YACd,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC;YAC/C,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,OAAO;IACT,CAAC;IAED,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,iBAAiB,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9C,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,GAAa,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AudioClip } from "../audio/track.js";
|
|
2
|
+
import type { Logger } from "../logger.js";
|
|
3
|
+
/**
|
|
4
|
+
* Add the audio `clips` onto the silent `videoPath`, writing `out`. Each clip is
|
|
5
|
+
* delayed to its `startMs` (`adelay`), gained (`volume`), then `amix`ed; the
|
|
6
|
+
* video is stream-copied and `-t` clamps the result to the video length.
|
|
7
|
+
*
|
|
8
|
+
* Per the timing contract the video defines the length: a clip that runs past
|
|
9
|
+
* the end is the author's cue to add a trailing `wait()`, so we warn and let
|
|
10
|
+
* `-t` truncate it rather than padding the video.
|
|
11
|
+
*/
|
|
12
|
+
export declare function addAudio(videoPath: string, clips: readonly AudioClip[], out: string, log: Logger): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=mix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mix.d.ts","sourceRoot":"","sources":["../../src/compose/mix.ts"],"names":[],"mappings":"AACA,OAAO,EAAmC,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAU3C;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getDuration, runFfmpeg } from "../ffmpeg.js";
|
|
2
|
+
import { audioFilterGraph, audioOverruns } from "../audio/track.js";
|
|
3
|
+
// ─── Compose layer: combining audio onto the video ───────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// `addAudio` lays the finished audio track onto the silent video — combining the
|
|
6
|
+
// two streams (the operation a pro A/V tool would call "muxing"). It lives in the
|
|
7
|
+
// compose layer because it joins layers; the audio layer only models the clips.
|
|
8
|
+
// Each clip is delayed to its position, gained, and mixed; the video is copied
|
|
9
|
+
// untouched.
|
|
10
|
+
/**
|
|
11
|
+
* Add the audio `clips` onto the silent `videoPath`, writing `out`. Each clip is
|
|
12
|
+
* delayed to its `startMs` (`adelay`), gained (`volume`), then `amix`ed; the
|
|
13
|
+
* video is stream-copied and `-t` clamps the result to the video length.
|
|
14
|
+
*
|
|
15
|
+
* Per the timing contract the video defines the length: a clip that runs past
|
|
16
|
+
* the end is the author's cue to add a trailing `wait()`, so we warn and let
|
|
17
|
+
* `-t` truncate it rather than padding the video.
|
|
18
|
+
*/
|
|
19
|
+
export async function addAudio(videoPath, clips, out, log) {
|
|
20
|
+
const videoMs = (await getDuration(videoPath)) * 1000;
|
|
21
|
+
for (const { path, overMs } of audioOverruns(clips, videoMs)) {
|
|
22
|
+
log("Audio", `warning: "${path}" runs ${overMs}ms past the video end and will be cut — ` +
|
|
23
|
+
`add a trailing wait() to give it room`);
|
|
24
|
+
}
|
|
25
|
+
const { filters, mapLabel } = audioFilterGraph(clips);
|
|
26
|
+
await runFfmpeg([
|
|
27
|
+
"-y",
|
|
28
|
+
"-i",
|
|
29
|
+
videoPath,
|
|
30
|
+
...clips.flatMap((c) => ["-i", c.path]),
|
|
31
|
+
"-filter_complex",
|
|
32
|
+
filters.join(";"),
|
|
33
|
+
"-map",
|
|
34
|
+
"0:v",
|
|
35
|
+
"-map",
|
|
36
|
+
`[${mapLabel}]`,
|
|
37
|
+
"-c:v",
|
|
38
|
+
"copy",
|
|
39
|
+
"-c:a",
|
|
40
|
+
"aac",
|
|
41
|
+
// The video defines the length: `-t` clamps the output to it, so short audio
|
|
42
|
+
// leaves trailing silence and an overrun is cut (not padded). (`-shortest`
|
|
43
|
+
// would wrongly truncate the video when the audio is shorter.)
|
|
44
|
+
"-t",
|
|
45
|
+
(videoMs / 1000).toFixed(3),
|
|
46
|
+
out,
|
|
47
|
+
]);
|
|
48
|
+
log("Audio", `mixed ${clips.length} audio clip(s)`);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=mix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mix.js","sourceRoot":"","sources":["../../src/compose/mix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAkB,MAAM,mBAAmB,CAAC;AAGpF,gFAAgF;AAChF,EAAE;AACF,iFAAiF;AACjF,kFAAkF;AAClF,gFAAgF;AAChF,+EAA+E;AAC/E,aAAa;AAEb;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,SAAiB,EACjB,KAA2B,EAC3B,GAAW,EACX,GAAW;IAEX,MAAM,OAAO,GAAG,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC;IACtD,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QAC7D,GAAG,CACD,OAAO,EACP,aAAa,IAAI,UAAU,MAAM,0CAA0C;YACzE,uCAAuC,CAC1C,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,SAAS,CAAC;QACd,IAAI;QACJ,IAAI;QACJ,SAAS;QACT,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACvC,iBAAiB;QACjB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QACjB,MAAM;QACN,KAAK;QACL,MAAM;QACN,IAAI,QAAQ,GAAG;QACf,MAAM;QACN,MAAM;QACN,MAAM;QACN,KAAK;QACL,6EAA6E;QAC7E,2EAA2E;QAC3E,+DAA+D;QAC/D,IAAI;QACJ,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3B,GAAG;KACJ,CAAC,CAAC;IACH,GAAG,CAAC,OAAO,EAAE,SAAS,KAAK,CAAC,MAAM,gBAAgB,CAAC,CAAC;AACtD,CAAC"}
|