termcut 0.6.4 → 0.7.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/src/video.ts CHANGED
@@ -3,8 +3,8 @@ import path from "node:path";
3
3
  import { readCast, writeCast } from "./cast";
4
4
  import { applyOverrides, resolveConfig } from "./config";
5
5
  import { record } from "./recorder";
6
- import { renderOutputs, type RenderResult } from "./render";
7
- import type { CastEvent, RecordOptions, Recording, RenderOptions, ResolvedConfig, Script, VideoConfig } from "./types";
6
+ import { renderSelection, type RenderResult } from "./render";
7
+ import type { CastEvent, ClipSelection, RecordOptions, Recording, RenderOptions, ResolvedConfig, Script, VideoConfig } from "./types";
8
8
 
9
9
  export interface VideoRecordOptions extends RecordOptions {
10
10
  /** Re-record even if a cached cast matches. */
@@ -69,8 +69,7 @@ export class Video {
69
69
  if (!(await file.exists())) return undefined;
70
70
  const hasher = new Bun.CryptoHasher("sha256");
71
71
  hasher.update(await file.arrayBuffer());
72
- const subset: Record<string, unknown> = {};
73
- for (const key of RECORD_KEYS) subset[key] = this.config[key];
72
+ const subset = Object.fromEntries(RECORD_KEYS.map((key) => [key, this.config[key]]));
74
73
  hasher.update(JSON.stringify(subset));
75
74
  return hasher.digest("hex");
76
75
  }
@@ -113,7 +112,7 @@ export class Video {
113
112
  async render(recording?: Recording, opts: RenderOptions = {}): Promise<RenderResult> {
114
113
  const rec = recording ?? (await readCast(this.config.cast));
115
114
  const config = applyOverrides(this.config, opts.overrides);
116
- return renderOutputs(rec, config, opts.onProgress);
115
+ return renderSelection(rec, config, opts.clip, opts.onProgress);
117
116
  }
118
117
 
119
118
  async run(opts: RunOptions = {}): Promise<RunResult> {
@@ -132,8 +131,9 @@ export function defineVideo(config: VideoConfig, script: Script): Video {
132
131
  return new Video(config, script);
133
132
  }
134
133
 
135
- export function isVideo(value: unknown): value is Video {
136
- return typeof value === "object" && value !== null && (value as { __bunVideo?: unknown }).__bunVideo === true;
134
+ /** True for a `defineVideo()` result checked by brand, so a Video built by another copy of tcut still counts. */
135
+ export function isVideo<T>(value: T): value is T & Video {
136
+ return value instanceof Object && "__bunVideo" in value && value.__bunVideo === true;
137
137
  }
138
138
 
139
139
  /** Render an existing .cast file (from tcut or asciinema) with the given settings. */
@@ -141,11 +141,14 @@ export async function renderCast(
141
141
  castFile: string,
142
142
  overrides: Partial<VideoConfig> & { output?: string | string[] },
143
143
  onProgress?: RenderOptions["onProgress"],
144
+ clip?: ClipSelection,
144
145
  ): Promise<RenderResult> {
145
146
  const rec = await readCast(castFile);
146
- const base =
147
- rec.header.bunVideo ??
148
- resolveConfig({ output: overrides.output ?? castFile.replace(/\.cast$/, "") + ".mp4", cols: rec.header.width, rows: rec.header.height });
149
- const config = applyOverrides(base, overrides);
150
- return renderOutputs(rec, config, onProgress);
147
+ const config = applyOverrides(castConfig(rec, castFile, overrides.output), overrides);
148
+ return renderSelection(rec, config, clip, onProgress);
149
+ }
150
+
151
+ /** The config a cast should be rendered with: the one recorded in its header, or sensible defaults for foreign casts. */
152
+ export function castConfig(rec: Recording, castFile: string, output?: string | string[]): ResolvedConfig {
153
+ return rec.header.bunVideo ?? resolveConfig({ output: output ?? castFile.replace(/\.cast$/, "") + ".mp4", cols: rec.header.width, rows: rec.header.height });
151
154
  }