recordable 0.4.0 → 0.5.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.
Files changed (47) hide show
  1. package/README.md +184 -30
  2. package/dist/actions.d.ts +7 -0
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +5 -0
  5. package/dist/actions.js.map +1 -1
  6. package/dist/audio/track.d.ts +10 -0
  7. package/dist/audio/track.d.ts.map +1 -1
  8. package/dist/audio/track.js +19 -0
  9. package/dist/audio/track.js.map +1 -1
  10. package/dist/compose/boundaries.d.ts +13 -0
  11. package/dist/compose/boundaries.d.ts.map +1 -0
  12. package/dist/compose/boundaries.js +49 -0
  13. package/dist/compose/boundaries.js.map +1 -0
  14. package/dist/compose/mix.d.ts +3 -2
  15. package/dist/compose/mix.d.ts.map +1 -1
  16. package/dist/compose/mix.js +8 -3
  17. package/dist/compose/mix.js.map +1 -1
  18. package/dist/compose/recordable.d.ts +24 -2
  19. package/dist/compose/recordable.d.ts.map +1 -1
  20. package/dist/compose/recordable.js +56 -11
  21. package/dist/compose/recordable.js.map +1 -1
  22. package/dist/compose/session.d.ts +19 -8
  23. package/dist/compose/session.d.ts.map +1 -1
  24. package/dist/compose/session.js +99 -28
  25. package/dist/compose/session.js.map +1 -1
  26. package/dist/ffmpeg.d.ts.map +1 -1
  27. package/dist/ffmpeg.js +8 -3
  28. package/dist/ffmpeg.js.map +1 -1
  29. package/dist/formats/json.d.ts +2 -1
  30. package/dist/formats/json.d.ts.map +1 -1
  31. package/dist/formats/json.js.map +1 -1
  32. package/dist/fs.d.ts +16 -0
  33. package/dist/fs.d.ts.map +1 -1
  34. package/dist/fs.js +33 -4
  35. package/dist/fs.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/result.d.ts +30 -0
  39. package/dist/result.d.ts.map +1 -0
  40. package/dist/result.js +8 -0
  41. package/dist/result.js.map +1 -0
  42. package/dist/video/recorder.d.ts +26 -3
  43. package/dist/video/recorder.d.ts.map +1 -1
  44. package/dist/video/recorder.js +43 -19
  45. package/dist/video/recorder.js.map +1 -1
  46. package/package.json +19 -6
  47. package/recordable.schema.json +78 -0
package/dist/fs.js CHANGED
@@ -17,14 +17,43 @@ export function moveFile(src, dest) {
17
17
  }
18
18
  }
19
19
  }
20
+ /** The optional `-YYYYMMDDhhmmss` suffix shared across a run's output files. */
21
+ function stamp(outputTimestamp) {
22
+ return outputTimestamp
23
+ ? "-" + new Date().toISOString().replace(/\D/g, "").slice(0, 14)
24
+ : "";
25
+ }
20
26
  /** Build the timestamped output path and ensure its directory exists. */
21
27
  export function getOutputPath(opts) {
22
28
  const { outputDir, outputName, outputTimestamp } = opts;
23
- const timestamp = outputTimestamp
24
- ? "-" + new Date().toISOString().replace(/\D/g, "").slice(0, 14)
25
- : "";
26
- const out = `${outputDir}/${outputName}${timestamp}.mp4`;
29
+ const out = `${outputDir}/${outputName}${stamp(outputTimestamp)}.mp4`;
27
30
  mkdirSync(dirname(out), { recursive: true });
28
31
  return out;
29
32
  }
33
+ /**
34
+ * Resolve the output path for each file of a multi-file run (ROADMAP §6),
35
+ * ensuring the directory exists. A single unlabelled file stays
36
+ * `<name>.mp4`; otherwise each file is suffixed — a label always wins
37
+ * (`<name>-intro.mp4`), an unlabelled file falls back to its 1-based position
38
+ * (`<name>-2.mp4`). One run-wide timestamp (when enabled) is shared by all.
39
+ * Collisions (e.g. a label equal to another's index) are disambiguated by
40
+ * appending the position.
41
+ */
42
+ export function resolveOutputPaths(opts, files) {
43
+ const { outputDir, outputName, outputTimestamp } = opts;
44
+ const ts = stamp(outputTimestamp);
45
+ const single = files.length === 1 && files[0].label == null;
46
+ const used = new Set();
47
+ const paths = files.map((f, i) => {
48
+ const suffix = single ? "" : `-${f.label ?? i + 1}`;
49
+ let name = `${outputName}${suffix}${ts}.mp4`;
50
+ if (used.has(name))
51
+ name = `${outputName}${suffix}-${i + 1}${ts}.mp4`;
52
+ used.add(name);
53
+ return `${outputDir}/${name}`;
54
+ });
55
+ if (paths.length)
56
+ mkdirSync(dirname(paths[0]), { recursive: true });
57
+ return paths;
58
+ }
30
59
  //# sourceMappingURL=fs.js.map
package/dist/fs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,IAAY;IAChD,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,IAI7B;IACC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACxD,MAAM,SAAS,GAAG,eAAe;QAC/B,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChE,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,UAAU,GAAG,SAAS,MAAM,CAAC;IACzD,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,IAAY;IAChD,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,SAAS,KAAK,CAAC,eAAwB;IACrC,OAAO,eAAe;QACpB,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChE,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,IAI7B;IACC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACxD,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,UAAU,GAAG,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC;IACtE,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAyE,EACzE,KAA0C;IAE1C,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACxD,MAAM,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;IAElC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;IAC5D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACpD,IAAI,IAAI,GAAG,GAAG,UAAU,GAAG,MAAM,GAAG,EAAE,MAAM,CAAC;QAC7C,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,GAAG,UAAU,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC;QACtE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,MAAM;QAAE,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC;AACf,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,4 +7,5 @@ export { buildSchema } from "./schema.js";
7
7
  export { parseMarkdown } from "./formats/markdown/parse.js";
8
8
  export type { ParsedMarkdown, MarkdownBlock, NarrationBlock, ActionsBlock, } from "./formats/markdown/parse.js";
9
9
  export type { RecordableConfig, VoiceoverConfig, AudioOptions, InsertOptions, WaitForOptions, ResolvedConfig, } from "./config.js";
10
+ export type { RecordableResult, RecordableFile } from "./result.js";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,30 @@
1
+ /** One written output file. */
2
+ export interface RecordableFile {
3
+ /** Absolute path to the .mp4. */
4
+ path: string;
5
+ /** The `start`/`split` label, or null when the file fell back to its position. */
6
+ label: string | null;
7
+ /** 1-based position among the written files. */
8
+ index: number;
9
+ /** Recorded length (ms), off-camera gaps excluded. */
10
+ durationMs: number;
11
+ /** File size in bytes. */
12
+ bytes: number;
13
+ }
14
+ /** What a successful `run()` resolves to. */
15
+ export interface RecordableResult {
16
+ /** `"completed"` when at least one file was written; `"empty"` when nothing
17
+ * was captured (no frames anywhere) and no file was written. */
18
+ status: "completed" | "empty";
19
+ /** The written files, in timeline order. Empty only when `status` is "empty". */
20
+ files: RecordableFile[];
21
+ /** The directory the files were written to. */
22
+ outputDir: string;
23
+ /** Total recorded length (ms) across all files. */
24
+ durationMs: number;
25
+ /** Wall-clock time the run took (ms). */
26
+ elapsedMs: number;
27
+ /** Non-fatal notes (skipped empty files, trimmed audio overruns). */
28
+ warnings: string[];
29
+ }
30
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAOA,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B;qEACiE;IACjE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAC9B,iFAAiF;IACjF,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
package/dist/result.js ADDED
@@ -0,0 +1,8 @@
1
+ // ─── Run result ──────────────────────────────────────────────────────────────
2
+ //
3
+ // What a successful run() resolves to. A run produces one or more output files
4
+ // (one per start/end/split boundary; one for a plain top-to-bottom script). Hard
5
+ // failures throw a RecordableError instead — so on the result `files` is always
6
+ // real and there is never two ways to model the same failure.
7
+ export {};
8
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,iFAAiF;AACjF,gFAAgF;AAChF,8DAA8D"}
@@ -2,6 +2,18 @@ import { type Page } from "puppeteer";
2
2
  import { type Logger } from "../logger.js";
3
3
  import { type InsertOptions, type ResolvedConfig } from "../config.js";
4
4
  import { type Segment } from "./stitch.js";
5
+ /** One output file's captured + inserted segments, with its place on the global
6
+ * recorded-time line (so audio clips can be partitioned and rebased per file). */
7
+ export interface OutputFile {
8
+ /** The `start`/`split` label, or null for an unlabelled / implicit file. */
9
+ label: string | null;
10
+ /** Segments in timeline order, for stitching. */
11
+ segments: Segment[];
12
+ /** Global recorded-time position (ms) where this file opened. */
13
+ startMs: number;
14
+ /** Recorded length (ms); set when the file closes. */
15
+ durationMs: number;
16
+ }
5
17
  /**
6
18
  * Recorded-time position now: finalised segment time plus the in-flight segment's
7
19
  * elapsed time (`frames / fps`). Off-camera (paused) stretches capture no frames,
@@ -12,7 +24,9 @@ export declare class Recorder {
12
24
  private readonly getCfg;
13
25
  private readonly log;
14
26
  private tmpDirPath;
15
- private segmentList;
27
+ private files;
28
+ private current;
29
+ private segCount;
16
30
  private currentSegment;
17
31
  private cdp;
18
32
  private cdpPage;
@@ -26,10 +40,19 @@ export declare class Recorder {
26
40
  constructor(getCfg: () => ResolvedConfig, log: Logger);
27
41
  /** True while a segment is actively capturing frames. */
28
42
  get capturing(): boolean;
29
- /** The captured + inserted segments, in timeline order (for stitching). */
30
- get segments(): Segment[];
43
+ /** True while an output file is open (capturing or paused). */
44
+ get fileOpen(): boolean;
45
+ /** The closed output files, in timeline order (for finalising). */
46
+ get outputFiles(): readonly OutputFile[];
31
47
  /** The temp working directory holding segment files. */
32
48
  get tmpDir(): string;
49
+ /** Open a new output file at the current recorded-time position. Segments
50
+ * captured/inserted from here on land in it until `closeFile`. */
51
+ openFile(label: string | null): void;
52
+ /** Seal the active segment and close the open file (recording its duration).
53
+ * An empty file (no captured frames) is still recorded so finalisation can
54
+ * report and skip it. No-op if no file is open. */
55
+ closeFile(): Promise<void>;
33
56
  /** Recorded-time position now: finalised segments + the in-flight segment. */
34
57
  currentTimelineMs(): number;
35
58
  /** Create the temp working directory for segment files. Call once before use. */
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/video/recorder.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,IAAI,EAAmB,MAAM,WAAW,CAAC;AAQvD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAa3C;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,GACjB,MAAM,CAGR;AAED,qBAAa,QAAQ;IAmBjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAnBtB,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,GAAG,CAA2B;IAEtC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,YAAY,CAAsB;IAG1C,OAAO,CAAC,WAAW,CAAK;gBAGL,MAAM,EAAE,MAAM,cAAc,EAC5B,GAAG,EAAE,MAAM;IAG9B,yDAAyD;IACzD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,2EAA2E;IAC3E,IAAI,QAAQ,IAAI,OAAO,EAAE,CAExB;IAED,wDAAwD;IACxD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,8EAA8E;IAC9E,iBAAiB,IAAI,MAAM;IAU3B,iFAAiF;IACjF,IAAI,IAAI,IAAI;IAIZ;;+EAE2E;YAC7D,UAAU;IAkBxB,wEAAwE;IAClE,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAoEtC;;iFAE6E;IACvE,GAAG,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA+CxC;;;;;;OAMG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCtE,sEAAsE;IAChE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,0EAA0E;IAC1E,SAAS,IAAI,IAAI;CAIlB"}
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/video/recorder.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,IAAI,EAAmB,MAAM,WAAW,CAAC;AAQvD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAmB3C;mFACmF;AACnF,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,GACjB,MAAM,CAGR;AAED,qBAAa,QAAQ;IAwBjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAxBtB,OAAO,CAAC,UAAU,CAAM;IAGxB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,GAAG,CAA2B;IAEtC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,YAAY,CAAsB;IAG1C,OAAO,CAAC,WAAW,CAAK;gBAGL,MAAM,EAAE,MAAM,cAAc,EAC5B,GAAG,EAAE,MAAM;IAG9B,yDAAyD;IACzD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,+DAA+D;IAC/D,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,mEAAmE;IACnE,IAAI,WAAW,IAAI,SAAS,UAAU,EAAE,CAEvC;IAED,wDAAwD;IACxD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;uEACmE;IACnE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAcpC;;wDAEoD;IAC9C,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAQhC,8EAA8E;IAC9E,iBAAiB,IAAI,MAAM;IAU3B,iFAAiF;IACjF,IAAI,IAAI,IAAI;IAIZ;;+EAE2E;YAC7D,UAAU;IAkBxB,wEAAwE;IAClE,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAoEtC;;iFAE6E;IACvE,GAAG,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA+CxC;;;;;;OAMG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CtE,sEAAsE;IAChE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,0EAA0E;IAC1E,SAAS,IAAI,IAAI;CAIlB"}
@@ -4,16 +4,6 @@ import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
  import { FFMPEG_PATH, getDuration, runFfmpeg, videoEncodeArgs, } from "../ffmpeg.js";
6
6
  import { RecordableError } from "../errors.js";
7
- // ─── Video layer: capture ────────────────────────────────────────────────────
8
- //
9
- // Captures the page via CDP `Page.startScreencast`, pipes JPEG frames into ffmpeg
10
- // at a steady fps to produce one MP4 per captured stretch, and tracks the
11
- // recorded-time clock the audio layer positions clips against. Stitching the
12
- // segments into the final video lives in `./stitch.ts`.
13
- //
14
- // Segments are started lazily and ended on pause, so off-camera gaps (page loads,
15
- // logins, data setup) leave no trace. Config is read through `getCfg` on each call
16
- // so runtime changes take effect.
17
7
  /**
18
8
  * Recorded-time position now: finalised segment time plus the in-flight segment's
19
9
  * elapsed time (`frames / fps`). Off-camera (paused) stretches capture no frames,
@@ -27,7 +17,12 @@ export class Recorder {
27
17
  getCfg;
28
18
  log;
29
19
  tmpDirPath = "";
30
- segmentList = [];
20
+ // Output files, in timeline order, plus the one currently open (null in an
21
+ // off-camera gap). Segments land in `current`; start/end/split manage the set.
22
+ files = [];
23
+ current = null;
24
+ // Monotonic segment counter for unique temp filenames across all files.
25
+ segCount = 0;
31
26
  currentSegment = "";
32
27
  cdp = null;
33
28
  // The page `cdp` is attached to — a new tab needs a fresh session (per-target).
@@ -49,14 +44,41 @@ export class Recorder {
49
44
  get capturing() {
50
45
  return this.ffmpegProc !== null;
51
46
  }
52
- /** The captured + inserted segments, in timeline order (for stitching). */
53
- get segments() {
54
- return this.segmentList;
47
+ /** True while an output file is open (capturing or paused). */
48
+ get fileOpen() {
49
+ return this.current !== null;
50
+ }
51
+ /** The closed output files, in timeline order (for finalising). */
52
+ get outputFiles() {
53
+ return this.files;
55
54
  }
56
55
  /** The temp working directory holding segment files. */
57
56
  get tmpDir() {
58
57
  return this.tmpDirPath;
59
58
  }
59
+ /** Open a new output file at the current recorded-time position. Segments
60
+ * captured/inserted from here on land in it until `closeFile`. */
61
+ openFile(label) {
62
+ if (this.current)
63
+ throw new RecordableError("CONFIG_INVALID", "openFile: a recording is already open");
64
+ this.current = {
65
+ label,
66
+ segments: [],
67
+ startMs: this.completedMs,
68
+ durationMs: 0,
69
+ };
70
+ }
71
+ /** Seal the active segment and close the open file (recording its duration).
72
+ * An empty file (no captured frames) is still recorded so finalisation can
73
+ * report and skip it. No-op if no file is open. */
74
+ async closeFile() {
75
+ await this.end(true); // seal the in-flight segment, no "pause" log
76
+ if (!this.current)
77
+ return;
78
+ this.current.durationMs = this.completedMs - this.current.startMs;
79
+ this.files.push(this.current);
80
+ this.current = null;
81
+ }
60
82
  /** Recorded-time position now: finalised segments + the in-flight segment. */
61
83
  currentTimelineMs() {
62
84
  const fps = this.segmentFps || this.getCfg().fps;
@@ -92,7 +114,7 @@ export class Recorder {
92
114
  if (this.ffmpegProc)
93
115
  return;
94
116
  const cfg = this.getCfg();
95
- const idx = this.segmentList.length;
117
+ const idx = this.segCount++;
96
118
  const file = join(this.tmpDirPath, `seg-${String(idx).padStart(3, "0")}.mp4`);
97
119
  const { width, height } = cfg.viewport;
98
120
  const fps = cfg.fps;
@@ -174,8 +196,8 @@ export class Recorder {
174
196
  throw new RecordableError("FFMPEG_FAILED", `recording capture failed: ${e.message}`, { cause: e });
175
197
  }
176
198
  // Only keep segments that actually captured frames (avoids empty/invalid mp4).
177
- if (this.currentSegment && frames > 0) {
178
- this.segmentList.push({
199
+ if (this.currentSegment && frames > 0 && this.current) {
200
+ this.current.segments.push({
179
201
  path: this.currentSegment,
180
202
  fadeIn: 0,
181
203
  fadeOut: 0,
@@ -199,8 +221,10 @@ export class Recorder {
199
221
  if (!existsSync(path))
200
222
  throw new RecordableError("FILE_NOT_FOUND", `insert: file not found: ${path}`);
201
223
  await this.end(true);
224
+ if (!this.current)
225
+ throw new RecordableError("CONFIG_INVALID", "insert: no open recording — call start() first");
202
226
  const cfg = this.getCfg();
203
- const idx = this.segmentList.length;
227
+ const idx = this.segCount++;
204
228
  const file = join(this.tmpDirPath, `seg-${String(idx).padStart(3, "0")}.mp4`);
205
229
  const { width, height } = cfg.viewport;
206
230
  // Letterbox-fit to the viewport and conform fps/codec/pixel format so the clip
@@ -218,7 +242,7 @@ export class Recorder {
218
242
  "yuv420p",
219
243
  file,
220
244
  ]);
221
- this.segmentList.push({
245
+ this.current.segments.push({
222
246
  path: file,
223
247
  fadeIn: Math.max(0, options.fadeIn ?? 0) / 1000,
224
248
  fadeOut: Math.max(0, options.fadeOut ?? 0) / 1000,
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/video/recorder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/video/recorder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recordable",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Programmatic, repeatable browser screen recording. Script a walkthrough as a fluent chain of actions — clicks, typing, smooth zoom/scroll, an animated cursor, and manual steps like logins — and capture it to MP4.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,15 +36,17 @@
36
36
  "scripts": {
37
37
  "build": "tsc",
38
38
  "typecheck": "tsc -p tsconfig.typecheck.json",
39
- "test": "tsx --test test/**/*.test.ts",
40
- "test:e2e": "tsx --test test/e2e/**/*.e2e.ts",
39
+ "test": "tsx --test test/*.test.ts",
40
+ "test:e2e": "tsx --test test/e2e/*.e2e.ts",
41
41
  "clean": "rm -rf dist",
42
42
  "gen:schema": "tsx scripts/gen-schema.ts",
43
43
  "lint": "eslint .",
44
44
  "lint:fix": "eslint . --fix",
45
45
  "format": "prettier --write .",
46
46
  "format:check": "prettier --check .",
47
- "prepublishOnly": "npm run clean && npm run gen:schema && npm run build"
47
+ "prepublishOnly": "npm run clean && npm run gen:schema && npm run build",
48
+ "commitlint": "commitlint",
49
+ "prepare": "husky && git config commit.template .gitmessage 2>/dev/null || true"
48
50
  },
49
51
  "keywords": [
50
52
  "screen-recording",
@@ -61,10 +63,10 @@
61
63
  "author": "Cam Parry <hello@camparry.com>",
62
64
  "license": "MIT",
63
65
  "engines": {
64
- "node": ">=18"
66
+ "node": ">=20"
65
67
  },
66
68
  "dependencies": {
67
- "@ffmpeg-installer/ffmpeg": "^1.1.0",
69
+ "ffmpeg-static": "^5.3.0",
68
70
  "gray-matter": "^4.0.3",
69
71
  "json5": "^2.2.3",
70
72
  "markdown-it": "^14.2.0",
@@ -72,11 +74,15 @@
72
74
  "zod": "^4.4.3"
73
75
  },
74
76
  "devDependencies": {
77
+ "@commitlint/cli": "^19.8.1",
78
+ "@commitlint/config-conventional": "^19.8.1",
75
79
  "@eslint/js": "^10.0.1",
76
80
  "@types/markdown-it": "^14.1.2",
77
81
  "@types/node": "^20.0.0",
78
82
  "eslint": "^10.5.0",
79
83
  "eslint-config-prettier": "^10.1.8",
84
+ "husky": "^9.1.7",
85
+ "lint-staged": "^15.5.2",
80
86
  "prettier": "^3.8.4",
81
87
  "tsx": "^4.0.0",
82
88
  "typescript": "^5.0.0",
@@ -84,5 +90,12 @@
84
90
  },
85
91
  "optionalDependencies": {
86
92
  "@elevenlabs/elevenlabs-js": "^2.0.0"
93
+ },
94
+ "lint-staged": {
95
+ "*.{ts,js,mjs,cjs}": [
96
+ "eslint --fix --no-warn-ignored",
97
+ "prettier --write"
98
+ ],
99
+ "*.{json,md,yml,yaml,css,html}": "prettier --write"
87
100
  }
88
101
  }
@@ -132,6 +132,9 @@
132
132
  "properties": {
133
133
  "action": {
134
134
  "enum": [
135
+ "start",
136
+ "end",
137
+ "split",
135
138
  "pause",
136
139
  "resume",
137
140
  "waitForPlay",
@@ -157,6 +160,81 @@
157
160
  }
158
161
  },
159
162
  "allOf": [
163
+ {
164
+ "if": {
165
+ "properties": {
166
+ "action": {
167
+ "const": "start"
168
+ }
169
+ },
170
+ "required": [
171
+ "action"
172
+ ]
173
+ },
174
+ "then": {
175
+ "properties": {
176
+ "action": {
177
+ "const": "start"
178
+ },
179
+ "name": {
180
+ "type": "string"
181
+ }
182
+ },
183
+ "required": [
184
+ "action"
185
+ ],
186
+ "additionalProperties": false
187
+ }
188
+ },
189
+ {
190
+ "if": {
191
+ "properties": {
192
+ "action": {
193
+ "const": "end"
194
+ }
195
+ },
196
+ "required": [
197
+ "action"
198
+ ]
199
+ },
200
+ "then": {
201
+ "properties": {
202
+ "action": {
203
+ "const": "end"
204
+ }
205
+ },
206
+ "required": [
207
+ "action"
208
+ ],
209
+ "additionalProperties": false
210
+ }
211
+ },
212
+ {
213
+ "if": {
214
+ "properties": {
215
+ "action": {
216
+ "const": "split"
217
+ }
218
+ },
219
+ "required": [
220
+ "action"
221
+ ]
222
+ },
223
+ "then": {
224
+ "properties": {
225
+ "action": {
226
+ "const": "split"
227
+ },
228
+ "name": {
229
+ "type": "string"
230
+ }
231
+ },
232
+ "required": [
233
+ "action"
234
+ ],
235
+ "additionalProperties": false
236
+ }
237
+ },
160
238
  {
161
239
  "if": {
162
240
  "properties": {