vargai 0.4.0-alpha56 → 0.4.0-alpha58

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/.env.example ADDED
@@ -0,0 +1,33 @@
1
+ # fal.ai api key
2
+ FAL_API_KEY=fal_xxx
3
+
4
+ # higgsfield credentials
5
+ HIGGSFIELD_API_KEY=hf_xxx
6
+ HIGGSFIELD_SECRET=secret_xxx
7
+
8
+ # elevenlabs api key
9
+ ELEVENLABS_API_KEY=el_xxx
10
+
11
+ # groq api key (ultra-fast whisper transcription)
12
+ GROQ_API_KEY=gsk_xxx
13
+
14
+ # fireworks api key (word-level transcription with timestamps)
15
+ FIREWORKS_API_KEY=fw_xxx
16
+
17
+ # cloudflare r2 / s3 storage
18
+ CLOUDFLARE_R2_API_URL=https://xxx.r2.cloudflarestorage.com
19
+ CLOUDFLARE_ACCESS_KEY_ID=xxx
20
+ CLOUDFLARE_ACCESS_SECRET=xxx
21
+ CLOUDFLARE_R2_BUCKET=m
22
+
23
+ # replicate (optional)
24
+ REPLICATE_API_TOKEN=r8_xxx
25
+
26
+ # apify (web scraping actors)
27
+ APIFY_TOKEN=apify_api_xxx
28
+
29
+ # decart ai (real-time & batch video/image)
30
+ DECART_API_KEY=decart_xxx
31
+
32
+ # together ai (fast flux-schnell, no queue)
33
+ TOGETHER_API_KEY=together_xxx
package/package.json CHANGED
@@ -70,7 +70,7 @@
70
70
  "zod": "^4.2.1"
71
71
  },
72
72
  "sideEffects": false,
73
- "version": "0.4.0-alpha56",
73
+ "version": "0.4.0-alpha58",
74
74
  "exports": {
75
75
  ".": "./src/index.ts",
76
76
  "./ai": "./src/ai-sdk/index.ts",
@@ -3,28 +3,17 @@ import type {
3
3
  FFmpegBackend,
4
4
  FFmpegOutput,
5
5
  } from "../../ai-sdk/providers/editly/backends/types";
6
- import { uploadBuffer } from "../../providers/storage";
7
6
 
8
7
  /**
9
- * Resolves an FFmpegOutput to a string path/URL, uploading local files if needed.
10
- *
11
- * - URL input → returns URL as-is
12
- * - File input + shouldUpload=false → returns local path
13
- * - File input + shouldUpload=true → uploads to storage, returns URL
8
+ * Resolves an FFmpegOutput to a string path/URL via the backend.
9
+ * Local backend returns local paths; cloud backends upload and return URLs.
14
10
  */
15
11
  async function resolveInputPathMaybeUpload(
16
12
  input: FFmpegOutput,
17
- options: { shouldUpload: boolean },
13
+ backend: FFmpegBackend,
18
14
  ): Promise<string> {
19
15
  if (input.type === "url") return input.url;
20
- if (!options.shouldUpload) return input.path;
21
-
22
- const buffer = await Bun.file(input.path).arrayBuffer();
23
- return uploadBuffer(
24
- buffer,
25
- `tmp/${Date.now()}-${input.path.split("/").pop()}`,
26
- "application/octet-stream",
27
- );
16
+ return backend.resolvePath(input.path);
28
17
  }
29
18
 
30
19
  export interface CaptionOverlayOptions {
@@ -69,22 +58,15 @@ export async function burnCaptions(
69
58
  const { video, assPath, outputPath = "output.mp4", verbose } = options;
70
59
  const captions: FFmpegOutput = { type: "file", path: assPath };
71
60
 
72
- // Resolve backend first so we can check if it's cloud or local
73
- // TODO: This is a hack - we should abstract backend capabilities (e.g., supportsLocalPaths)
74
- // instead of checking the name directly. For now, we assume "local" is the only local backend.
75
61
  const backend = options.backend ?? localBackend;
76
- const isCloud = backend.name !== "local";
77
62
 
78
- const videoInput = await resolveInputPathMaybeUpload(video, {
79
- shouldUpload: isCloud,
80
- });
81
- const assInput = await resolveInputPathMaybeUpload(captions, {
82
- shouldUpload: isCloud,
83
- });
63
+ const videoInput = await resolveInputPathMaybeUpload(video, backend);
64
+ const assInput = await resolveInputPathMaybeUpload(captions, backend);
84
65
 
85
66
  // For cloud backends (Rendi): pass raw URL so replaceWithPlaceholders() can match
86
67
  // and replace with {{in_X}} placeholder. Rendi downloads inputs and provides local paths.
87
68
  // For local backend: escape for FFmpeg filter syntax (backslashes and colons)
69
+ const isCloud = backend.name !== "local";
88
70
  const subtitlesPath = isCloud
89
71
  ? assInput
90
72
  : assInput.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
@@ -4,7 +4,6 @@ import type {
4
4
  FFmpegBackend,
5
5
  FFmpegOutput,
6
6
  } from "../../../ai-sdk/providers/editly/backends/types";
7
- import { uploadBuffer } from "../../../providers/storage";
8
7
 
9
8
  export interface BlinkingButtonOptions {
10
9
  text: string;
@@ -107,18 +106,15 @@ function oscExpr(tv: string, P: number): string {
107
106
  }
108
107
 
109
108
  /**
110
- * Resolve a local file path to a URL for cloud backends.
109
+ * Resolve a local file path to a string path/URL via the backend.
111
110
  * Local backend: returns the path as-is.
112
- * Cloud backend: uploads the file and returns the URL.
111
+ * Cloud backend (Rendi): uploads via its StorageProvider and returns the URL.
113
112
  */
114
113
  async function resolvePathForBackend(
115
114
  localPath: string,
116
115
  backend: FFmpegBackend,
117
116
  ): Promise<string> {
118
- if (backend.name === "local") return localPath;
119
- const buffer = await Bun.file(localPath).arrayBuffer();
120
- const key = `tmp/${Date.now()}-${localPath.split("/").pop()}`;
121
- return uploadBuffer(buffer, key, "image/png");
117
+ return backend.resolvePath(localPath);
122
118
  }
123
119
 
124
120
  // ─── Main ────────────────────────────────────────────────────────────────────
@@ -1,5 +1,8 @@
1
1
  import { editly } from "../../ai-sdk/providers/editly";
2
- import type { FFmpegOutput } from "../../ai-sdk/providers/editly/backends/types";
2
+ import type {
3
+ FFmpegBackend,
4
+ FFmpegOutput,
5
+ } from "../../ai-sdk/providers/editly/backends/types";
3
6
  import type {
4
7
  Clip,
5
8
  ImageOverlayLayer,
@@ -9,27 +12,21 @@ import type {
9
12
  SizeValue,
10
13
  TitleLayer,
11
14
  } from "../../ai-sdk/providers/editly/types";
12
- import { uploadBuffer } from "../../providers/storage";
13
15
  import type { PackshotProps, VargElement } from "../types";
14
16
  import type { RenderContext } from "./context";
15
17
  import { renderImage } from "./image";
16
18
  import { createBlinkingButton } from "./packshot/blinking-button";
17
19
 
18
20
  /**
19
- * Resolve an FFmpegOutput to a string path/URL, uploading local files for cloud backends.
21
+ * Resolve an FFmpegOutput to a string path/URL via the backend.
22
+ * Local backend returns local paths; cloud backends upload and return URLs.
20
23
  */
21
24
  async function resolveInputMaybeUpload(
22
25
  input: FFmpegOutput,
23
- shouldUpload: boolean,
26
+ backend: FFmpegBackend,
24
27
  ): Promise<string> {
25
28
  if (input.type === "url") return input.url;
26
- if (!shouldUpload) return input.path;
27
- const buffer = await Bun.file(input.path).arrayBuffer();
28
- return uploadBuffer(
29
- buffer,
30
- `tmp/${Date.now()}-${input.path.split("/").pop()}`,
31
- "application/octet-stream",
32
- );
29
+ return backend.resolvePath(input.path);
33
30
  }
34
31
 
35
32
  /**
@@ -178,7 +175,7 @@ export async function renderPackshot(
178
175
 
179
176
  const basePath = `/tmp/varg-packshot-${Date.now()}.mp4`;
180
177
 
181
- await editly({
178
+ const baseResult = await editly({
182
179
  outPath: basePath,
183
180
  width: ctx.width,
184
181
  height: ctx.height,
@@ -207,12 +204,11 @@ export async function renderPackshot(
207
204
  );
208
205
 
209
206
  // Composite button overlay at correct position on base video via backend
210
- const isCloud = ctx.backend.name !== "local";
211
207
  const baseInput = await resolveInputMaybeUpload(
212
- { type: "file", path: basePath },
213
- isCloud,
208
+ baseResult.output,
209
+ ctx.backend,
214
210
  );
215
- const btnInput = await resolveInputMaybeUpload(btn.output, isCloud);
211
+ const btnInput = await resolveInputMaybeUpload(btn.output, ctx.backend);
216
212
 
217
213
  const finalPath = `/tmp/varg-packshot-final-${Date.now()}.mp4`;
218
214
 
@@ -237,10 +233,10 @@ export async function renderPackshot(
237
233
  return overlayResult.output.path;
238
234
  }
239
235
  // Cloud backend returns URL
240
- ctx.tempFiles.push(basePath);
241
236
  return overlayResult.output.url;
242
237
  }
243
238
 
239
+ if (baseResult.output.type === "url") return baseResult.output.url;
244
240
  ctx.tempFiles.push(basePath);
245
241
  return basePath;
246
242
  }