@mevdragon/vidfarm-devcli 0.20.9 → 0.20.11
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.
|
@@ -121,7 +121,7 @@ If a local AI script rewrites text or scenes without consuming those files first
|
|
|
121
121
|
| `vidfarm generate <image\|video> --prompt "…"` | `POST /api/v1/primitives/{images,videos}/generate` (polls job) | generate AI media → finished URL |
|
|
122
122
|
| `vidfarm inpaint <image> --mask <png> --prompt "…" [--region "label=…"] [--ref …] [--out <f>]` | `POST /api/v1/primitives/images/inpaint` (polls job) | masked image EDIT — replace ONLY the transparent-mask region, keep everything else (devcli twin of the /inpaint page) |
|
|
123
123
|
| `vidfarm create-overlay "<subject>" [--key-color #00FF00] [--aspect-ratio 1:1] [--place <dir>] [--out <f>]` | `POST /api/v1/primitives/images/create-overlay` (polls job) | **Vox-style** transparent OVERLAY — AI image on a forced key-color background, chroma-keyed out in one job → ready-to-composite transparent PNG |
|
|
124
|
-
| `vidfarm remove-
|
|
124
|
+
| `vidfarm remove-greenscreen <image\|video> [--preset green\|blue\|white\|black\|digital-green\|magenta] [--key-color #00FF00] [--tolerance 0.3] [--local] [--out <f>]` | `POST /api/v1/primitives/remove-greenscreen` (polls job) | chroma-key a FLAT solid background → transparent PNG/WebP (image) or WebM/VP9-alpha (video); auto-detects media kind. `--local` runs it FREE in-process (sharp/ffmpeg, no wallet); default cloud is billed at real compute × 1.2. Aliases: `greenscreen`, `remove-background-greenscreen`. |
|
|
125
125
|
| `vidfarm tts "…" [--style "…"] [--voice <v>] [--out <file>]` | (LOCAL-FIRST: your own OPENAI/GEMINI/OPENROUTER_API_KEY → audio file on disk; `--cloud` = `POST /api/v1/primitives/audio/speech` + poll, ElevenLabs on the platform key by default, `--own-key` for yours) | text → narration audio; `--cloud --voice <voice_id>` picks an ElevenLabs voice |
|
|
126
126
|
| `vidfarm music "<prompt>" [--length <sec>] [--out <f>] [--own-key]` | `POST /api/v1/primitives/music/generate` (polls job) | prompt → music track (ElevenLabs; platform key + wallet by default, `--own-key` for yours) |
|
|
127
127
|
| `vidfarm voices [--own-key] [--limit N]` | `GET /api/v1/primitives/audio/voices` | list ElevenLabs voices (voice_id/name/labels) for `tts --voice`; default a voice + tell the user they can choose |
|
|
@@ -17,18 +17,17 @@ curl -X POST "$VIDFARM_BASE/api/v1/primitives/images/remove-background" \
|
|
|
17
17
|
-d '{"source_image_url": "https://cdn.example.com/photo.jpg"}'
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
## Primitive:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- `POST /api/v1/primitives/
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
- `
|
|
28
|
-
- `
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
- Billing: small compute-only wallet fee (`greenscreen_chroma_key` cost center) — cheaper than the RapidAPI route.
|
|
20
|
+
## Primitive: remove-greenscreen (image **or** video chroma-key)
|
|
21
|
+
|
|
22
|
+
**Local chroma-key** background removal for an IMAGE **or** a VIDEO — no third-party API, so it costs a fraction of `image_remove_background`. Use it whenever the source sits on a **flat, solid, evenly-lit background**: a green screen, or any single fill color. An IMAGE returns a transparent PNG/WebP; a VIDEO returns a transparent **WebM (VP9 alpha)** that stays transparent in the `/editor` preview AND the final render (it composites over whatever layers sit behind it).
|
|
23
|
+
|
|
24
|
+
- **Unified (auto-detect):** `POST /api/v1/primitives/remove-greenscreen` — detects image vs video from the source and dispatches. Preferred entry point.
|
|
25
|
+
- Image-only: `POST /api/v1/primitives/images/remove-background-greenscreen` (flat alias: `POST /api/v1/primitives/remove-background-greenscreen`). Video-only: `POST /api/v1/primitives/videos/remove-greenscreen`.
|
|
26
|
+
- Body: `{ "tracer": "...", "payload": { "source_url": "https://..." (image OR video), "media_type"?: "image" | "video" (skip auto-detect), "preset"?: "green" | "digital-green" | "blue" | "white" | "black" | "magenta", "key_color"?: "#00FF00", "tolerance"?: 0.3, "softness"?: 0.1, "despill"?: true, "output_format"?: "png" | "webp" (image only) }, "webhook_url"?: "..." }`
|
|
27
|
+
- `preset` — pick a common background color by name; fills `key_color` + tuned defaults. `key_color` (hex / `rgb(...)` / named) overrides the preset for a custom color/range.
|
|
28
|
+
- `tolerance` (0–1) — how close a pixel must be to key it out. Raise it if fringe survives, lower it if the subject is eaten. `softness` (0–1) feathers the edge; `despill` (default `true`) trims the residual key-color rim (green/blue only).
|
|
29
|
+
- Response: standard primitive job; poll, then read `primary_file_url` (a `.png/.webp` for image, `.webm` for video). After keying, `set_layer_media` the URL back onto the source layer to swap the transparent cut-out in place.
|
|
30
|
+
- Billing: the **real measured AWS compute cost × 1.2** (`greenscreen_chroma_key` cost center) — no flat fee. Far cheaper than the RapidAPI matting route.
|
|
32
31
|
|
|
33
32
|
## Primitive: media_overlay ("create media overlay" — Vox-style)
|
|
34
33
|
|
package/SKILL.director.md
CHANGED
|
@@ -986,7 +986,7 @@ If a local AI script rewrites text or scenes without consuming those files first
|
|
|
986
986
|
| `vidfarm generate <image\|video> --prompt "…"` | `POST /api/v1/primitives/{images,videos}/generate` (polls job) | generate AI media → finished URL |
|
|
987
987
|
| `vidfarm inpaint <image> --mask <png> --prompt "…" [--region "label=…"] [--ref …] [--out <f>]` | `POST /api/v1/primitives/images/inpaint` (polls job) | masked image EDIT — replace ONLY the transparent-mask region, keep everything else (devcli twin of the /inpaint page) |
|
|
988
988
|
| `vidfarm create-overlay "<subject>" [--key-color #00FF00] [--aspect-ratio 1:1] [--place <dir>] [--out <f>]` | `POST /api/v1/primitives/images/create-overlay` (polls job) | **Vox-style** transparent OVERLAY — AI image on a forced key-color background, chroma-keyed out in one job → ready-to-composite transparent PNG |
|
|
989
|
-
| `vidfarm remove-
|
|
989
|
+
| `vidfarm remove-greenscreen <image\|video> [--preset green\|blue\|white\|black\|digital-green\|magenta] [--key-color #00FF00] [--tolerance 0.3] [--local] [--out <f>]` | `POST /api/v1/primitives/remove-greenscreen` (polls job) | chroma-key a FLAT solid background → transparent PNG/WebP (image) or WebM/VP9-alpha (video); auto-detects media kind. `--local` runs it FREE in-process (sharp/ffmpeg, no wallet); default cloud is billed at real compute × 1.2. Aliases: `greenscreen`, `remove-background-greenscreen`. |
|
|
990
990
|
| `vidfarm tts "…" [--style "…"] [--voice <v>] [--out <file>]` | (LOCAL-FIRST: your own OPENAI/GEMINI/OPENROUTER_API_KEY → audio file on disk; `--cloud` = `POST /api/v1/primitives/audio/speech` + poll, ElevenLabs on the platform key by default, `--own-key` for yours) | text → narration audio; `--cloud --voice <voice_id>` picks an ElevenLabs voice |
|
|
991
991
|
| `vidfarm music "<prompt>" [--length <sec>] [--out <f>] [--own-key]` | `POST /api/v1/primitives/music/generate` (polls job) | prompt → music track (ElevenLabs; platform key + wallet by default, `--own-key` for yours) |
|
|
992
992
|
| `vidfarm voices [--own-key] [--limit N]` | `GET /api/v1/primitives/audio/voices` | list ElevenLabs voices (voice_id/name/labels) for `tts --voice`; default a voice + tell the user they can choose |
|
|
@@ -1157,18 +1157,17 @@ curl -X POST "$VIDFARM_BASE/api/v1/primitives/images/remove-background" \
|
|
|
1157
1157
|
-d '{"source_image_url": "https://cdn.example.com/photo.jpg"}'
|
|
1158
1158
|
```
|
|
1159
1159
|
|
|
1160
|
-
## Primitive:
|
|
1160
|
+
## Primitive: remove-greenscreen (image **or** video chroma-key)
|
|
1161
1161
|
|
|
1162
|
-
|
|
1162
|
+
**Local chroma-key** background removal for an IMAGE **or** a VIDEO — no third-party API, so it costs a fraction of `image_remove_background`. Use it whenever the source sits on a **flat, solid, evenly-lit background**: a green screen, or any single fill color. An IMAGE returns a transparent PNG/WebP; a VIDEO returns a transparent **WebM (VP9 alpha)** that stays transparent in the `/editor` preview AND the final render (it composites over whatever layers sit behind it).
|
|
1163
1163
|
|
|
1164
|
-
- `POST /api/v1/primitives/
|
|
1165
|
-
-
|
|
1166
|
-
|
|
1167
|
-
- `
|
|
1168
|
-
- `
|
|
1169
|
-
|
|
1170
|
-
-
|
|
1171
|
-
- Billing: small compute-only wallet fee (`greenscreen_chroma_key` cost center) — cheaper than the RapidAPI route.
|
|
1164
|
+
- **Unified (auto-detect):** `POST /api/v1/primitives/remove-greenscreen` — detects image vs video from the source and dispatches. Preferred entry point.
|
|
1165
|
+
- Image-only: `POST /api/v1/primitives/images/remove-background-greenscreen` (flat alias: `POST /api/v1/primitives/remove-background-greenscreen`). Video-only: `POST /api/v1/primitives/videos/remove-greenscreen`.
|
|
1166
|
+
- Body: `{ "tracer": "...", "payload": { "source_url": "https://..." (image OR video), "media_type"?: "image" | "video" (skip auto-detect), "preset"?: "green" | "digital-green" | "blue" | "white" | "black" | "magenta", "key_color"?: "#00FF00", "tolerance"?: 0.3, "softness"?: 0.1, "despill"?: true, "output_format"?: "png" | "webp" (image only) }, "webhook_url"?: "..." }`
|
|
1167
|
+
- `preset` — pick a common background color by name; fills `key_color` + tuned defaults. `key_color` (hex / `rgb(...)` / named) overrides the preset for a custom color/range.
|
|
1168
|
+
- `tolerance` (0–1) — how close a pixel must be to key it out. Raise it if fringe survives, lower it if the subject is eaten. `softness` (0–1) feathers the edge; `despill` (default `true`) trims the residual key-color rim (green/blue only).
|
|
1169
|
+
- Response: standard primitive job; poll, then read `primary_file_url` (a `.png/.webp` for image, `.webm` for video). After keying, `set_layer_media` the URL back onto the source layer to swap the transparent cut-out in place.
|
|
1170
|
+
- Billing: the **real measured AWS compute cost × 1.2** (`greenscreen_chroma_key` cost center) — no flat fee. Far cheaper than the RapidAPI matting route.
|
|
1172
1171
|
|
|
1173
1172
|
## Primitive: media_overlay ("create media overlay" — Vox-style)
|
|
1174
1173
|
|
package/dist/src/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import { renderCompositionStills } from "./devcli/stills.js";
|
|
|
22
22
|
import { runDoctorCommand } from "./devcli/doctor.js";
|
|
23
23
|
import { runSkillsCommand } from "./devcli/skills.js";
|
|
24
24
|
import { initTelemetry, reportCliCrash } from "./devcli/telemetry.js";
|
|
25
|
-
import { resolveLocalDataDir, localBackendAvailable, LocalModeUnavailableError } from "./devcli/local-backend.js";
|
|
25
|
+
import { resolveLocalDataDir, localBackendAvailable, LocalModeUnavailableError, localApiRequest } from "./devcli/local-backend.js";
|
|
26
26
|
// vidfarm-devcli — command-line bridge for the Vidfarm video studio. The
|
|
27
27
|
// `serve` command boots the FULL editor locally (single origin, disk-backed
|
|
28
28
|
// records + storage) so power users edit compositions on disk while a browser
|
|
@@ -172,14 +172,20 @@ Generate AI media and drop it on the timeline (for local coding agents):
|
|
|
172
172
|
--out <file> Download the transparent PNG to this path
|
|
173
173
|
--no-wait Return the job id instead of polling to the URL
|
|
174
174
|
--place <dir> --at <time>|--replace <layer_key> Fuse onto a composition
|
|
175
|
-
remove-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
remove-greenscreen <image|video|url> Key out a FLAT solid background from an
|
|
176
|
+
IMAGE (→ transparent PNG/WebP) or VIDEO (→ transparent
|
|
177
|
+
WebM/VP9 alpha), auto-detecting the media kind.
|
|
178
|
+
(aliases: greenscreen, remove-background-greenscreen)
|
|
179
|
+
→ POST /api/v1/primitives/remove-greenscreen
|
|
180
|
+
--preset <name> green | digital-green | blue | white | black | magenta
|
|
181
|
+
--key-color <c> Custom background color (hex/rgb/named; overrides --preset)
|
|
182
|
+
--media-type <k> Force image|video instead of auto-detecting
|
|
180
183
|
--tolerance <0..1> Key radius (default 0.3); --softness <0..1> edge feather (0.1)
|
|
181
184
|
--no-despill Skip edge color-fringe suppression
|
|
182
|
-
--
|
|
185
|
+
--output-format <f> Image only: png|webp
|
|
186
|
+
--local Run the keyer in-process for FREE (sharp/ffmpeg, no wallet)
|
|
187
|
+
--cloud Force the billed cloud primitive (default when a key is set)
|
|
188
|
+
--out <file> Download the transparent result to this path
|
|
183
189
|
place <dir|composition.html> Insert media into a local composition
|
|
184
190
|
(fill a gap, replace a scene, or overlay an AUDIO
|
|
185
191
|
track) — same clip markup the browser editor makes;
|
|
@@ -667,10 +673,11 @@ async function main() {
|
|
|
667
673
|
case "overlay":
|
|
668
674
|
await runCreateOverlayCommand(rest);
|
|
669
675
|
return;
|
|
676
|
+
case "remove-greenscreen":
|
|
670
677
|
case "remove-background-greenscreen":
|
|
671
678
|
case "rmbg-green":
|
|
672
679
|
case "greenscreen":
|
|
673
|
-
await
|
|
680
|
+
await runRemoveGreenscreenCommand(rest);
|
|
674
681
|
return;
|
|
675
682
|
case "tts":
|
|
676
683
|
await runTtsCommand(rest);
|
|
@@ -3585,33 +3592,67 @@ async function runCreateOverlayCommand(argv) {
|
|
|
3585
3592
|
}
|
|
3586
3593
|
}
|
|
3587
3594
|
// ── Green-screen (chroma-key) background removal ──────────────────────────────
|
|
3588
|
-
// The devcli twin of the
|
|
3589
|
-
//
|
|
3590
|
-
//
|
|
3591
|
-
|
|
3595
|
+
// The devcli twin of the remove-greenscreen primitive: key out a flat, solid
|
|
3596
|
+
// background from an IMAGE (→ transparent PNG/WebP) OR a VIDEO (→ transparent
|
|
3597
|
+
// WebM/VP9 alpha), auto-detecting the media kind. LOCAL vs CLOUD: --local runs
|
|
3598
|
+
// the keyer in-process for FREE (sharp/ffmpeg, no wallet); --cloud runs the
|
|
3599
|
+
// billed primitive. Default = cloud (paid), unless there's no cloud key AND the
|
|
3600
|
+
// local backend is present (free / offline), in which case it runs local.
|
|
3601
|
+
const GREENSCREEN_PRESET_NAMES = new Set(["green", "digital-green", "blue", "white", "black", "magenta"]);
|
|
3602
|
+
function resolveGreenscreenTarget(values) {
|
|
3603
|
+
if (values.local)
|
|
3604
|
+
return "local";
|
|
3605
|
+
if (values.cloud)
|
|
3606
|
+
return "cloud";
|
|
3607
|
+
const env = (process.env.VIDFARM_TARGET ?? "").trim().toLowerCase();
|
|
3608
|
+
if (env === "local" || env === "cloud")
|
|
3609
|
+
return env;
|
|
3610
|
+
const hasCloudKey = Boolean(values["api-key"] ?? process.env.VIDFARM_API_KEY);
|
|
3611
|
+
if (!hasCloudKey && localBackendAvailable())
|
|
3612
|
+
return "local";
|
|
3613
|
+
return "cloud";
|
|
3614
|
+
}
|
|
3615
|
+
async function runRemoveGreenscreenCommand(argv) {
|
|
3592
3616
|
const parsed = parseArgs({
|
|
3593
3617
|
args: argv,
|
|
3594
3618
|
allowPositionals: true,
|
|
3595
3619
|
options: {
|
|
3596
3620
|
...commonOptions(),
|
|
3597
3621
|
source: { type: "string" },
|
|
3622
|
+
preset: { type: "string" },
|
|
3623
|
+
"media-type": { type: "string" },
|
|
3598
3624
|
"key-color": { type: "string" },
|
|
3599
3625
|
tolerance: { type: "string" },
|
|
3600
3626
|
softness: { type: "string" },
|
|
3601
3627
|
"no-despill": { type: "boolean", default: false },
|
|
3602
3628
|
"output-format": { type: "string" },
|
|
3629
|
+
local: { type: "boolean", default: false },
|
|
3630
|
+
cloud: { type: "boolean", default: false },
|
|
3603
3631
|
out: { type: "string" },
|
|
3604
3632
|
"no-wait": { type: "boolean", default: false },
|
|
3605
3633
|
tracer: { type: "string" }
|
|
3606
3634
|
}
|
|
3607
3635
|
});
|
|
3608
3636
|
const ctx = commonContext(parsed.values);
|
|
3637
|
+
const target = resolveGreenscreenTarget(parsed.values);
|
|
3638
|
+
if (target === "local" && !localBackendAvailable())
|
|
3639
|
+
throw new LocalModeUnavailableError();
|
|
3609
3640
|
const sourceArg = parsed.values.source ?? parsed.positionals[0];
|
|
3610
3641
|
if (!sourceArg) {
|
|
3611
|
-
throw new Error("remove-
|
|
3642
|
+
throw new Error("remove-greenscreen requires a source image or video: `vidfarm remove-greenscreen <image|video|url> [--preset green|blue|white|black|digital-green|magenta] [--key-color #00FF00] [--local] [--out cutout.png|.webm]`.");
|
|
3612
3643
|
}
|
|
3613
3644
|
const sourceUrl = await resolveSingleMediaUrl(ctx, sourceArg);
|
|
3614
|
-
const
|
|
3645
|
+
const presetRaw = parsed.values.preset?.trim().toLowerCase();
|
|
3646
|
+
if (presetRaw && !GREENSCREEN_PRESET_NAMES.has(presetRaw)) {
|
|
3647
|
+
throw new Error(`Unknown --preset "${presetRaw}". Choose one of: ${[...GREENSCREEN_PRESET_NAMES].join(", ")}, or pass --key-color <hex>.`);
|
|
3648
|
+
}
|
|
3649
|
+
const mediaTypeArg = parsed.values["media-type"]?.trim().toLowerCase();
|
|
3650
|
+
const mediaType = mediaTypeArg === "image" || mediaTypeArg === "video"
|
|
3651
|
+
? mediaTypeArg
|
|
3652
|
+
: (/\.(mp4|mov|webm|m4v|mkv)(\?|#|$)/i.test(sourceUrl) ? "video" : "image");
|
|
3653
|
+
const payload = { source_url: sourceUrl, media_type: mediaType };
|
|
3654
|
+
if (presetRaw)
|
|
3655
|
+
payload.preset = presetRaw;
|
|
3615
3656
|
if (parsed.values["key-color"])
|
|
3616
3657
|
payload.key_color = parsed.values["key-color"];
|
|
3617
3658
|
if (parsed.values.tolerance)
|
|
@@ -3620,12 +3661,17 @@ async function runRemoveBackgroundGreenscreenCommand(argv) {
|
|
|
3620
3661
|
payload.softness = Number(parsed.values.softness);
|
|
3621
3662
|
if (parsed.values["no-despill"])
|
|
3622
3663
|
payload.despill = false;
|
|
3623
|
-
if (parsed.values["output-format"])
|
|
3664
|
+
if (mediaType === "image" && parsed.values["output-format"])
|
|
3624
3665
|
payload.output_format = parsed.values["output-format"];
|
|
3625
|
-
const tracer = parsed.values.tracer ?? `devcli-
|
|
3626
|
-
const
|
|
3627
|
-
|
|
3666
|
+
const tracer = parsed.values.tracer ?? `devcli-greenscreen-${Date.now().toString(36)}`;
|
|
3667
|
+
const route = "/api/v1/primitives/remove-greenscreen";
|
|
3668
|
+
const submit = target === "local"
|
|
3669
|
+
? await localApiRequest({ method: "POST", path: route, auth: ctx.auth, body: { tracer, payload }, home: ctx.home })
|
|
3670
|
+
: await apiRequest({ method: "POST", host: ctx.host, path: route, auth: ctx.auth, body: { tracer, payload } });
|
|
3671
|
+
assertApiOk(submit, "remove-greenscreen");
|
|
3628
3672
|
const jobId = submit.json?.job_id;
|
|
3673
|
+
if (!ctx.json)
|
|
3674
|
+
console.log(`${DIM}${target === "local" ? "Local (free)" : "Cloud"} ${mediaType} greenscreen removal…${RESET}`);
|
|
3629
3675
|
const wait = !parsed.values["no-wait"];
|
|
3630
3676
|
if (!wait || !jobId) {
|
|
3631
3677
|
if (!ctx.json && jobId)
|
|
@@ -3635,7 +3681,7 @@ async function runRemoveBackgroundGreenscreenCommand(argv) {
|
|
|
3635
3681
|
}
|
|
3636
3682
|
if (!ctx.json)
|
|
3637
3683
|
console.log(`${DIM}Keying out background (${jobId})… polling every 5s.${RESET}`);
|
|
3638
|
-
const job = await
|
|
3684
|
+
const job = await pollGreenscreenJob(ctx, target, jobId);
|
|
3639
3685
|
const mediaUrl = resolveJobMediaUrl(job);
|
|
3640
3686
|
const status = String(job?.status ?? "");
|
|
3641
3687
|
if (!mediaUrl) {
|
|
@@ -3655,12 +3701,38 @@ async function runRemoveBackgroundGreenscreenCommand(argv) {
|
|
|
3655
3701
|
await downloadUrlToFile(mediaUrl, outPath);
|
|
3656
3702
|
}
|
|
3657
3703
|
if (ctx.json) {
|
|
3658
|
-
printJson({ ok: true, job_id: jobId, media_url: mediaUrl, out: outPath
|
|
3704
|
+
printJson({ ok: true, job_id: jobId, media_type: mediaType, target, media_url: mediaUrl, out: outPath });
|
|
3659
3705
|
}
|
|
3660
3706
|
else {
|
|
3661
|
-
console.log(`${GREEN}Transparent cut-out ready:${RESET} ${mediaUrl}`);
|
|
3707
|
+
console.log(`${GREEN}Transparent ${mediaType === "video" ? "WebM" : "cut-out"} ready:${RESET} ${mediaUrl}`);
|
|
3662
3708
|
if (outPath)
|
|
3663
3709
|
console.log(`${DIM}Saved to ${outPath}${RESET}`);
|
|
3710
|
+
console.log(`${DIM}Place it with: vidfarm set-media <dir> --src "${mediaUrl}" --replace <layer_key> (keeps its transparency).${RESET}`);
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
// Poll a greenscreen job through the same backend it was submitted to (local
|
|
3714
|
+
// in-process app or cloud). Mirrors pollPrimitiveJob's terminal conditions.
|
|
3715
|
+
async function pollGreenscreenJob(ctx, target, jobId) {
|
|
3716
|
+
if (target !== "local")
|
|
3717
|
+
return pollPrimitiveJob(ctx, jobId);
|
|
3718
|
+
const MAX_WAIT_MS = 8 * 60 * 1000;
|
|
3719
|
+
const startedAt = Date.now();
|
|
3720
|
+
let last = null;
|
|
3721
|
+
for (;;) {
|
|
3722
|
+
await sleep(5000);
|
|
3723
|
+
const res = await localApiRequest({ method: "GET", path: `/api/v1/user/me/jobs/${encodeURIComponent(jobId)}`, auth: ctx.auth, home: ctx.home });
|
|
3724
|
+
if (res.ok && res.json) {
|
|
3725
|
+
last = res.json;
|
|
3726
|
+
const status = String(last.status ?? "");
|
|
3727
|
+
if (!ctx.json)
|
|
3728
|
+
console.log(`${DIM} ${status}${typeof last.progress === "number" ? ` ${Math.round(last.progress * 100)}%` : ""}${RESET}`);
|
|
3729
|
+
if (status === "succeeded" || status === "failed" || status === "cancelled")
|
|
3730
|
+
return last;
|
|
3731
|
+
if (resolveJobMediaUrl(last))
|
|
3732
|
+
return last;
|
|
3733
|
+
}
|
|
3734
|
+
if (Date.now() - startedAt > MAX_WAIT_MS)
|
|
3735
|
+
return last ?? { status: "timeout" };
|
|
3664
3736
|
}
|
|
3665
3737
|
}
|
|
3666
3738
|
// ── Speech: tts / stt ────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mevdragon/vidfarm-devcli",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.11",
|
|
4
4
|
"description": "Local bridge for the Vidfarm Trackpad Editor. `vidfarm serve <template_id>` boots the FULL editor on localhost (disk-backed records/storage, free in-process render); edit composition.html on disk (Claude Code, Codex, etc.) and the browser live-morphs it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|