@officexapp/vidfarm-devcli 0.21.21 → 0.21.22
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/.agents/skills/vidfarm/SKILL.md +1 -0
- package/.agents/skills/vidfarm/references/assets-and-sourcing.md +17 -0
- package/.agents/skills/vidfarm/references/automation-and-local-dev.md +5 -3
- package/.agents/skills/vidfarm/references/primitives.md +21 -7
- package/SKILL.director.md +44 -10
- package/SKILL.md +1 -0
- package/dist/src/cli.js +55 -4
- package/package.json +1 -1
|
@@ -221,6 +221,7 @@ Choose the narrowest path that satisfies the request.
|
|
|
221
221
|
2. If the user already knows the goal and needs a suitable template, read `references/core-workflows.md` and use the template discovery flow.
|
|
222
222
|
3. If the task is “change this video,” read `references/editor-workflows.md`.
|
|
223
223
|
4. If the task is “find footage” or “use our existing assets,” read `references/assets-and-sourcing.md`.
|
|
224
|
+
4b. If the task is **“download this video/audio off a website”** (a pasted YouTube / TikTok / Instagram / X post URL the user wants the actual file from), Vidfarm does that for you on a **paid plan** — `POST /api/v1/primitives/videos/download` (or `/audio/download`), devcli `vidfarm download-video <url>` / `vidfarm download-audio <url>`. **Free plan → do not call it; walk the user through opening the URL in Chrome and downloading it from the page, then `vidfarm put-file` the local file in for $0.** Details in `references/assets-and-sourcing.md` → `references/primitives.md`.
|
|
224
225
|
5. If the task is scripted, local, CI-driven, or `vidfarm serve`-based, read `references/automation-and-local-dev.md`.
|
|
225
226
|
6. If the task explicitly asks for a primitive or needs specialized generation/transcription work, read `references/primitives.md`.
|
|
226
227
|
7. If the task is the MARKETPLACE (ordering videos from specialist agents): browsing is web-only for paying customers — send the human to https://vidfarm.cc/marketplace, never render it locally. Placing/listing orders is the thin REST wrapper in `references/core-workflows.md` (§ Marketplace); anything deeper on a gig (inbox, proofs, payouts) needs the external Dollar Platoon skill — `npx skills add https://github.com/OfficeXApp/dollarplatoon-skill` — the same way FlockPoster work beyond scheduling needs `npx skills add https://github.com/OfficeXApp/flockposter-skill`.
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## Download a video from a website (Vidfarm fetches it for you — paid plans)
|
|
2
|
+
|
|
3
|
+
**Yes, Vidfarm can download videos off the web for the user.** When someone pastes a YouTube / TikTok / Instagram / X (Twitter) / other supported post URL and wants the actual file — "grab this video", "save this clip", "get me that audio" — you do **not** need yt-dlp, a browser extension, or an apology. One primitive does it and returns a durable Vidfarm-hosted asset:
|
|
4
|
+
|
|
5
|
+
| Want | Call | devcli |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| The video (or a photo/carousel post → ordered slideshow) | `POST /api/v1/primitives/videos/download` `{ tracer, payload: { source_url, quality?: "best"\|"hd"\|"full_hd" } }` | `vidfarm download-video <url>` |
|
|
8
|
+
| Just the audio/music/voice track | `POST /api/v1/primitives/audio/download` `{ tracer, payload: { source_url } }` | `vidfarm download-audio <url>` |
|
|
9
|
+
|
|
10
|
+
Both are async primitive jobs — poll `GET /api/v1/primitives/jobs/:jobId` until `succeeded`, then read `primary_file_url`. Full field-level detail (slideshow response shape, billing, examples) lives in `references/primitives.md`.
|
|
11
|
+
|
|
12
|
+
**PAID PLANS ONLY.** These ride a paid third-party resolver billed to the wallet, so a free-plan customer gets `402 insufficient_funds`. Check the plan / cost mode before promising it.
|
|
13
|
+
|
|
14
|
+
**Free-plan users — the fallback is Chrome, and it works:** tell them (or, if you have browser automation, do it yourself) to **open the URL in Chrome and download the video from there** — right-click → *Save video as*, the downloads pane, DevTools → Network, or a Googled `"<platform> video downloader"` site in that same session. Then bring the local file in for free with `vidfarm put-file ./the-file.mp4 --folder <folder>` or the web uploader. Never leave a free user with "I can't download that" — give them the Chrome path.
|
|
15
|
+
|
|
16
|
+
**Don't reach for this when the real goal is clips.** If the user wants short clips mined out of a long video, `POST /raws/scan` with `source_url` already downloads the source for you as part of the hunt (below) — a separate download call is wasted spend.
|
|
17
|
+
|
|
1
18
|
## Raws (long-form → short-form raws)
|
|
2
19
|
|
|
3
20
|
Mine a **long-form** video (podcast, stream VOD, webinar, any YouTube/TikTok/IG/X URL, or an upload) into a library of tagged, searchable **raws**. This is the `/raws` surface — browse it at `https://vidfarm.cc/library/raws` (the Library page's "Approved / Raws" tabs).
|
|
@@ -175,9 +175,11 @@ The licensed harness also carries the **generative build workflow** guidance (ch
|
|
|
175
175
|
| `vidfarm wallet [--job <id>\|--tracer <t>] [--limit <n>]` | `GET /api/v1/user/me/wallet` | cost log: balance + lifetime spend + recent charges. `--job <renderJobId>` prints **what that one video cost** (sums its charges); `--tracer <t>` sums a tracer. Cloud-only, paid plan. Aliases: `spend`, `costs` |
|
|
176
176
|
| `vidfarm provider-keys` / `vidfarm add-provider-key <p> <secret>` | `GET`·`POST /api/v1/user/me/provider-keys` | manage AI keys |
|
|
177
177
|
| `vidfarm upload <file> [--folder <path>]` | presign → S3 PUT → finalize (`.../temporary-files/presign` + `.../temporary-files`) | upload → durable URL (ephemeral, 30-day TTL; prefer `--folder temp` for scratch). Goes direct to S3, so large files (up to **200 MB**) bypass the ~6 MB Lambda body limit |
|
|
178
|
-
| `vidfarm download <url> [dest]` | (streams any URL to disk) | download media |
|
|
179
|
-
| `vidfarm download-
|
|
180
|
-
| `vidfarm download-
|
|
178
|
+
| `vidfarm download <url> [dest]` | (streams any URL to disk) | download media from a **direct** media URL. Free — no plan, no job |
|
|
179
|
+
| `vidfarm download-video <url> [--quality best\|hd\|full_hd]` | `POST /api/v1/primitives/videos/download` + poll | **download a video FROM A WEBSITE** (YouTube/TikTok/IG/X/other supported posts) into durable Vidfarm media; photo/carousel posts return an ordered slideshow. **PAID PLAN** (wallet-billed resolver; free plans get 402). Aliases: `download-post`, `download-url` |
|
|
180
|
+
| `vidfarm download-audio <url>` | `POST /api/v1/primitives/audio/download` + poll | download just the AUDIO track (music/voice) off a website post into a durable audio file. **PAID PLAN**. Alias: `download-post-audio` |
|
|
181
|
+
|
|
182
|
+
> **Free plan / `cost-mode minimize`:** both download commands are gated by `guardBilled` and will refuse or warn. The free path is **Chrome**: open the URL in a real browser, save the file off the page (right-click → *Save video as*, downloads pane, or a Googled `"<platform> video downloader"` site), then `vidfarm put-file ./the-file.mp4 --folder <folder>` to bring it in for $0. The CLI prints these steps on a 402. Never tell a free user the video simply can't be downloaded.
|
|
181
183
|
| `vidfarm files [--folder <path>]` | `GET /api/v1/user/me/attachments` | list My Files assets + folders |
|
|
182
184
|
| `vidfarm files --search "…" [--folder <path>]` | `POST /api/v1/user/me/attachments/search` | find My Files assets by MEANING (keyword + vector over name/folder/notes) |
|
|
183
185
|
| `vidfarm get-file <id> [dest] [--print]` | (resolve id → view_url, then stream/print) | read one My Files asset |
|
|
@@ -51,9 +51,11 @@ curl -X POST "$VIDFARM_BASE/api/v1/primitives/images/create-overlay" \
|
|
|
51
51
|
-d '{"tracer": "vox-overlay", "payload": {"prompt": "a friendly cartoon lightbulb mascot, flat vector illustration", "aspect_ratio": "1:1"}}'
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
## Primitive: videos/download
|
|
54
|
+
## Primitive: videos/download — **Vidfarm downloads videos off websites for you**
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
**Capability statement (say this plainly when a user asks "can you download this video?"): yes — on a paid plan, Vidfarm downloads a video straight off a website URL for you.** Hand it a YouTube / TikTok / Instagram / X (Twitter) / other supported post URL and it returns a durable Vidfarm-hosted file. No local yt-dlp, no browser extension, no "I can't access that URL." The route is intentionally broader than its old name suggests: it returns either a normal MP4 for video posts, or a slideshow payload for photo/carousel posts.
|
|
57
|
+
|
|
58
|
+
**Paid-only, and that gate is real.** The resolver is a paid RapidAPI pass-through billed to the wallet, so a free-plan customer gets `402 insufficient_funds`. Never promise this to a free user — route them to the browser fallback below instead.
|
|
57
59
|
|
|
58
60
|
- `POST /api/v1/primitives/videos/download`
|
|
59
61
|
- Body: `{ "tracer": "...", "payload": { "source_url": "https://...", "quality"?: "best" | "hd" | "full_hd", "save_manifest"?: true }, "webhook_url"?: "..." }`
|
|
@@ -61,8 +63,20 @@ Download a supported social/media post URL into a durable Vidfarm-hosted VISUAL
|
|
|
61
63
|
- Video post: read `primary_file_url` / `video.file_url` / `videoUrl` for the durable MP4.
|
|
62
64
|
- Photo/carousel post: read `mediaKind: "slideshow"`, ordered `slideImageUrls[]`, optional `slideAudioUrl`, and `primary_file_url` (first slide image).
|
|
63
65
|
- Billing: RapidAPI pass-through wallet charge (`rapidapi_video_download`) plus the small mirror/extract pass (`video_download_lambda` when MP4 download is involved).
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
+
- devcli wrapper: `vidfarm download-video <url> [--quality best|hd|full_hd]` (aliases: `download-post`, `download-url`)
|
|
67
|
+
|
|
68
|
+
### FREE-PLAN FALLBACK — drive Chrome instead (never dead-end the user)
|
|
69
|
+
|
|
70
|
+
If the user is on the free plan, says "don't spend money", or cost mode is `minimize`, do **not** call this route. **Load the URL in Chrome and download it by that means** — it costs $0.00 and needs no Vidfarm plan:
|
|
71
|
+
|
|
72
|
+
1. Open the post/page in Chrome. A real browser session carries the login/consent/age walls that a bare `fetch` can't.
|
|
73
|
+
2. Save the video off the page — right-click → *Save video as*, the browser's downloads pane, or DevTools → Network → the media response.
|
|
74
|
+
3. If the page won't hand it over, Google `"youtube video downloader"` (or `"tiktok/instagram/x/twitter video downloader"`) and use one of those sites in the same Chrome session.
|
|
75
|
+
4. Bring the resulting local file into Vidfarm for free: `vidfarm put-file ./the-file.mp4 --folder <folder>` (devcli) or the web app's upload. From there it's a normal durable asset.
|
|
76
|
+
|
|
77
|
+
If you're a desktop coding agent with browser automation (Playwright/Puppeteer/CDP, or the user's own Chrome), you can perform steps 1–3 yourself. If you're the web copilot with no browser tool, hand the user these steps — do not claim you downloaded it.
|
|
78
|
+
|
|
79
|
+
Say the tradeoff out loud once: *"Downloading it for you is a paid-plan feature; on the free plan I'll walk you through grabbing it in Chrome instead."*
|
|
66
80
|
|
|
67
81
|
Example:
|
|
68
82
|
|
|
@@ -81,9 +95,9 @@ Download just the original audio/music/voice track from a supported social/media
|
|
|
81
95
|
- Body: `{ "tracer": "...", "payload": { "source_url": "https://...", "save_manifest"?: true }, "webhook_url"?: "..." }`
|
|
82
96
|
- Response: standard primitive job. Poll `GET /api/v1/primitives/jobs/:jobId` until `status: "succeeded"`, then read `primary_file_url` / `audio.file_url` / `audioUrl`.
|
|
83
97
|
- Behavior: prefers the provider's direct audio track when present; otherwise resolves the source video and extracts audio server-side.
|
|
84
|
-
- Billing: same RapidAPI wallet class as `videos/download`.
|
|
85
|
-
- Free-plan / no-spend rule:
|
|
86
|
-
- devcli wrapper: `vidfarm download-
|
|
98
|
+
- Billing: same RapidAPI wallet class as `videos/download` — **paid plans only**; free plans get `402`.
|
|
99
|
+
- Free-plan / no-spend rule: identical to the visual route — **load the URL in Chrome and download from there**, then `vidfarm put-file` the result. Google `"youtube audio downloader"` or `"tiktok/twitter/instagram/etc audio downloader"` if the page won't release the track. See the FREE-PLAN FALLBACK block above.
|
|
100
|
+
- devcli wrapper: `vidfarm download-audio <url>` (alias: `download-post-audio`)
|
|
87
101
|
|
|
88
102
|
Example:
|
|
89
103
|
|
package/SKILL.director.md
CHANGED
|
@@ -221,6 +221,7 @@ Choose the narrowest path that satisfies the request.
|
|
|
221
221
|
2. If the user already knows the goal and needs a suitable template, read `references/core-workflows.md` and use the template discovery flow.
|
|
222
222
|
3. If the task is “change this video,” read `references/editor-workflows.md`.
|
|
223
223
|
4. If the task is “find footage” or “use our existing assets,” read `references/assets-and-sourcing.md`.
|
|
224
|
+
4b. If the task is **“download this video/audio off a website”** (a pasted YouTube / TikTok / Instagram / X post URL the user wants the actual file from), Vidfarm does that for you on a **paid plan** — `POST /api/v1/primitives/videos/download` (or `/audio/download`), devcli `vidfarm download-video <url>` / `vidfarm download-audio <url>`. **Free plan → do not call it; walk the user through opening the URL in Chrome and downloading it from the page, then `vidfarm put-file` the local file in for $0.** Details in `references/assets-and-sourcing.md` → `references/primitives.md`.
|
|
224
225
|
5. If the task is scripted, local, CI-driven, or `vidfarm serve`-based, read `references/automation-and-local-dev.md`.
|
|
225
226
|
6. If the task explicitly asks for a primitive or needs specialized generation/transcription work, read `references/primitives.md`.
|
|
226
227
|
7. If the task is the MARKETPLACE (ordering videos from specialist agents): browsing is web-only for paying customers — send the human to https://vidfarm.cc/marketplace, never render it locally. Placing/listing orders is the thin REST wrapper in `references/core-workflows.md` (§ Marketplace); anything deeper on a gig (inbox, proofs, payouts) needs the external Dollar Platoon skill — `npx skills add https://github.com/OfficeXApp/dollarplatoon-skill` — the same way FlockPoster work beyond scheduling needs `npx skills add https://github.com/OfficeXApp/flockposter-skill`.
|
|
@@ -1020,6 +1021,23 @@ For anything bespoke, pass raw stops: `vidfarm keyframes ./work --layer robot --
|
|
|
1020
1021
|
|
|
1021
1022
|
**Pick the store by lifetime.** A throwaway intermediate (cloud render source, a `place` scratch asset) belongs in the 30-day `temp/` store: `vidfarm upload clip.mp4 --folder temp`, `vidfarm place … --folder temp` — quarantined in one place you can periodically purge. Anything you **approve/share is permanent**, so `vidfarm approve --video ./final.mp4` uploads to **durable My Files** by default (the share video would otherwise 404 after the temp store's 30-day deletion). Only add `vidfarm approve --temp` when you deliberately want a disposable 30-day preview.
|
|
1022
1023
|
|
|
1024
|
+
## Download a video from a website (Vidfarm fetches it for you — paid plans)
|
|
1025
|
+
|
|
1026
|
+
**Yes, Vidfarm can download videos off the web for the user.** When someone pastes a YouTube / TikTok / Instagram / X (Twitter) / other supported post URL and wants the actual file — "grab this video", "save this clip", "get me that audio" — you do **not** need yt-dlp, a browser extension, or an apology. One primitive does it and returns a durable Vidfarm-hosted asset:
|
|
1027
|
+
|
|
1028
|
+
| Want | Call | devcli |
|
|
1029
|
+
| --- | --- | --- |
|
|
1030
|
+
| The video (or a photo/carousel post → ordered slideshow) | `POST /api/v1/primitives/videos/download` `{ tracer, payload: { source_url, quality?: "best"\|"hd"\|"full_hd" } }` | `vidfarm download-video <url>` |
|
|
1031
|
+
| Just the audio/music/voice track | `POST /api/v1/primitives/audio/download` `{ tracer, payload: { source_url } }` | `vidfarm download-audio <url>` |
|
|
1032
|
+
|
|
1033
|
+
Both are async primitive jobs — poll `GET /api/v1/primitives/jobs/:jobId` until `succeeded`, then read `primary_file_url`. Full field-level detail (slideshow response shape, billing, examples) lives in `references/primitives.md`.
|
|
1034
|
+
|
|
1035
|
+
**PAID PLANS ONLY.** These ride a paid third-party resolver billed to the wallet, so a free-plan customer gets `402 insufficient_funds`. Check the plan / cost mode before promising it.
|
|
1036
|
+
|
|
1037
|
+
**Free-plan users — the fallback is Chrome, and it works:** tell them (or, if you have browser automation, do it yourself) to **open the URL in Chrome and download the video from there** — right-click → *Save video as*, the downloads pane, DevTools → Network, or a Googled `"<platform> video downloader"` site in that same session. Then bring the local file in for free with `vidfarm put-file ./the-file.mp4 --folder <folder>` or the web uploader. Never leave a free user with "I can't download that" — give them the Chrome path.
|
|
1038
|
+
|
|
1039
|
+
**Don't reach for this when the real goal is clips.** If the user wants short clips mined out of a long video, `POST /raws/scan` with `source_url` already downloads the source for you as part of the hunt (below) — a separate download call is wasted spend.
|
|
1040
|
+
|
|
1023
1041
|
## Raws (long-form → short-form raws)
|
|
1024
1042
|
|
|
1025
1043
|
Mine a **long-form** video (podcast, stream VOD, webinar, any YouTube/TikTok/IG/X URL, or an upload) into a library of tagged, searchable **raws**. This is the `/raws` surface — browse it at `https://vidfarm.cc/library/raws` (the Library page's "Approved / Raws" tabs).
|
|
@@ -1321,9 +1339,11 @@ The licensed harness also carries the **generative build workflow** guidance (ch
|
|
|
1321
1339
|
| `vidfarm wallet [--job <id>\|--tracer <t>] [--limit <n>]` | `GET /api/v1/user/me/wallet` | cost log: balance + lifetime spend + recent charges. `--job <renderJobId>` prints **what that one video cost** (sums its charges); `--tracer <t>` sums a tracer. Cloud-only, paid plan. Aliases: `spend`, `costs` |
|
|
1322
1340
|
| `vidfarm provider-keys` / `vidfarm add-provider-key <p> <secret>` | `GET`·`POST /api/v1/user/me/provider-keys` | manage AI keys |
|
|
1323
1341
|
| `vidfarm upload <file> [--folder <path>]` | presign → S3 PUT → finalize (`.../temporary-files/presign` + `.../temporary-files`) | upload → durable URL (ephemeral, 30-day TTL; prefer `--folder temp` for scratch). Goes direct to S3, so large files (up to **200 MB**) bypass the ~6 MB Lambda body limit |
|
|
1324
|
-
| `vidfarm download <url> [dest]` | (streams any URL to disk) | download media |
|
|
1325
|
-
| `vidfarm download-
|
|
1326
|
-
| `vidfarm download-
|
|
1342
|
+
| `vidfarm download <url> [dest]` | (streams any URL to disk) | download media from a **direct** media URL. Free — no plan, no job |
|
|
1343
|
+
| `vidfarm download-video <url> [--quality best\|hd\|full_hd]` | `POST /api/v1/primitives/videos/download` + poll | **download a video FROM A WEBSITE** (YouTube/TikTok/IG/X/other supported posts) into durable Vidfarm media; photo/carousel posts return an ordered slideshow. **PAID PLAN** (wallet-billed resolver; free plans get 402). Aliases: `download-post`, `download-url` |
|
|
1344
|
+
| `vidfarm download-audio <url>` | `POST /api/v1/primitives/audio/download` + poll | download just the AUDIO track (music/voice) off a website post into a durable audio file. **PAID PLAN**. Alias: `download-post-audio` |
|
|
1345
|
+
|
|
1346
|
+
> **Free plan / `cost-mode minimize`:** both download commands are gated by `guardBilled` and will refuse or warn. The free path is **Chrome**: open the URL in a real browser, save the file off the page (right-click → *Save video as*, downloads pane, or a Googled `"<platform> video downloader"` site), then `vidfarm put-file ./the-file.mp4 --folder <folder>` to bring it in for $0. The CLI prints these steps on a 402. Never tell a free user the video simply can't be downloaded.
|
|
1327
1347
|
| `vidfarm files [--folder <path>]` | `GET /api/v1/user/me/attachments` | list My Files assets + folders |
|
|
1328
1348
|
| `vidfarm files --search "…" [--folder <path>]` | `POST /api/v1/user/me/attachments/search` | find My Files assets by MEANING (keyword + vector over name/folder/notes) |
|
|
1329
1349
|
| `vidfarm get-file <id> [dest] [--print]` | (resolve id → view_url, then stream/print) | read one My Files asset |
|
|
@@ -1556,9 +1576,11 @@ curl -X POST "$VIDFARM_BASE/api/v1/primitives/images/create-overlay" \
|
|
|
1556
1576
|
-d '{"tracer": "vox-overlay", "payload": {"prompt": "a friendly cartoon lightbulb mascot, flat vector illustration", "aspect_ratio": "1:1"}}'
|
|
1557
1577
|
```
|
|
1558
1578
|
|
|
1559
|
-
## Primitive: videos/download
|
|
1579
|
+
## Primitive: videos/download — **Vidfarm downloads videos off websites for you**
|
|
1580
|
+
|
|
1581
|
+
**Capability statement (say this plainly when a user asks "can you download this video?"): yes — on a paid plan, Vidfarm downloads a video straight off a website URL for you.** Hand it a YouTube / TikTok / Instagram / X (Twitter) / other supported post URL and it returns a durable Vidfarm-hosted file. No local yt-dlp, no browser extension, no "I can't access that URL." The route is intentionally broader than its old name suggests: it returns either a normal MP4 for video posts, or a slideshow payload for photo/carousel posts.
|
|
1560
1582
|
|
|
1561
|
-
|
|
1583
|
+
**Paid-only, and that gate is real.** The resolver is a paid RapidAPI pass-through billed to the wallet, so a free-plan customer gets `402 insufficient_funds`. Never promise this to a free user — route them to the browser fallback below instead.
|
|
1562
1584
|
|
|
1563
1585
|
- `POST /api/v1/primitives/videos/download`
|
|
1564
1586
|
- Body: `{ "tracer": "...", "payload": { "source_url": "https://...", "quality"?: "best" | "hd" | "full_hd", "save_manifest"?: true }, "webhook_url"?: "..." }`
|
|
@@ -1566,8 +1588,20 @@ Download a supported social/media post URL into a durable Vidfarm-hosted VISUAL
|
|
|
1566
1588
|
- Video post: read `primary_file_url` / `video.file_url` / `videoUrl` for the durable MP4.
|
|
1567
1589
|
- Photo/carousel post: read `mediaKind: "slideshow"`, ordered `slideImageUrls[]`, optional `slideAudioUrl`, and `primary_file_url` (first slide image).
|
|
1568
1590
|
- Billing: RapidAPI pass-through wallet charge (`rapidapi_video_download`) plus the small mirror/extract pass (`video_download_lambda` when MP4 download is involved).
|
|
1569
|
-
-
|
|
1570
|
-
|
|
1591
|
+
- devcli wrapper: `vidfarm download-video <url> [--quality best|hd|full_hd]` (aliases: `download-post`, `download-url`)
|
|
1592
|
+
|
|
1593
|
+
### FREE-PLAN FALLBACK — drive Chrome instead (never dead-end the user)
|
|
1594
|
+
|
|
1595
|
+
If the user is on the free plan, says "don't spend money", or cost mode is `minimize`, do **not** call this route. **Load the URL in Chrome and download it by that means** — it costs $0.00 and needs no Vidfarm plan:
|
|
1596
|
+
|
|
1597
|
+
1. Open the post/page in Chrome. A real browser session carries the login/consent/age walls that a bare `fetch` can't.
|
|
1598
|
+
2. Save the video off the page — right-click → *Save video as*, the browser's downloads pane, or DevTools → Network → the media response.
|
|
1599
|
+
3. If the page won't hand it over, Google `"youtube video downloader"` (or `"tiktok/instagram/x/twitter video downloader"`) and use one of those sites in the same Chrome session.
|
|
1600
|
+
4. Bring the resulting local file into Vidfarm for free: `vidfarm put-file ./the-file.mp4 --folder <folder>` (devcli) or the web app's upload. From there it's a normal durable asset.
|
|
1601
|
+
|
|
1602
|
+
If you're a desktop coding agent with browser automation (Playwright/Puppeteer/CDP, or the user's own Chrome), you can perform steps 1–3 yourself. If you're the web copilot with no browser tool, hand the user these steps — do not claim you downloaded it.
|
|
1603
|
+
|
|
1604
|
+
Say the tradeoff out loud once: *"Downloading it for you is a paid-plan feature; on the free plan I'll walk you through grabbing it in Chrome instead."*
|
|
1571
1605
|
|
|
1572
1606
|
Example:
|
|
1573
1607
|
|
|
@@ -1586,9 +1620,9 @@ Download just the original audio/music/voice track from a supported social/media
|
|
|
1586
1620
|
- Body: `{ "tracer": "...", "payload": { "source_url": "https://...", "save_manifest"?: true }, "webhook_url"?: "..." }`
|
|
1587
1621
|
- Response: standard primitive job. Poll `GET /api/v1/primitives/jobs/:jobId` until `status: "succeeded"`, then read `primary_file_url` / `audio.file_url` / `audioUrl`.
|
|
1588
1622
|
- Behavior: prefers the provider's direct audio track when present; otherwise resolves the source video and extracts audio server-side.
|
|
1589
|
-
- Billing: same RapidAPI wallet class as `videos/download`.
|
|
1590
|
-
- Free-plan / no-spend rule:
|
|
1591
|
-
- devcli wrapper: `vidfarm download-
|
|
1623
|
+
- Billing: same RapidAPI wallet class as `videos/download` — **paid plans only**; free plans get `402`.
|
|
1624
|
+
- Free-plan / no-spend rule: identical to the visual route — **load the URL in Chrome and download from there**, then `vidfarm put-file` the result. Google `"youtube audio downloader"` or `"tiktok/twitter/instagram/etc audio downloader"` if the page won't release the track. See the FREE-PLAN FALLBACK block above.
|
|
1625
|
+
- devcli wrapper: `vidfarm download-audio <url>` (alias: `download-post-audio`)
|
|
1592
1626
|
|
|
1593
1627
|
Example:
|
|
1594
1628
|
|
package/SKILL.md
CHANGED
|
@@ -73,6 +73,7 @@ For composition *authoring* craft (motion, keyframes, scene design), Vidfarm shi
|
|
|
73
73
|
2. "Find a template and start" → `references/core-workflows.md`
|
|
74
74
|
3. "Change / re-theme this video" → `references/editor-workflows.md`
|
|
75
75
|
4. "Find footage / use our assets" → `references/assets-and-sourcing.md`
|
|
76
|
+
4b. **"Download this video/audio from <a website URL>"** → Vidfarm fetches it for you on a **paid plan**: `POST /api/v1/primitives/videos/download` (or `/audio/download`); devcli `vidfarm download-video <url>` / `vidfarm download-audio <url>`. Works on YouTube, TikTok, Instagram, X, and other supported posts; returns a durable Vidfarm file (photo/carousel posts → an ordered slideshow). **Free plan gets a 402 — don't call it. Tell the user (or, with browser automation, do it yourself) to open the URL in Chrome and download it from the page, then `vidfarm put-file ./the-file.mp4` to bring it in for $0.** Never answer "I can't download that." Details: `references/assets-and-sourcing.md`.
|
|
76
77
|
5. "Script / batch / render loop" → `references/automation-and-local-dev.md`
|
|
77
78
|
6. "I need TTS / music / captions / background removal" → `references/primitives.md`
|
|
78
79
|
|
package/dist/src/cli.js
CHANGED
|
@@ -600,12 +600,19 @@ Files (multi-step flows the devcli handles for you):
|
|
|
600
600
|
--notes <text> Metadata notes (what it is / when to use it) — vector-embedded for search
|
|
601
601
|
e.g. vidfarm put-file About.md --folder acme-skincare
|
|
602
602
|
echo "..." | vidfarm put-file --stdin --as About.md --folder acme
|
|
603
|
-
download <url> [dest] Stream any Vidfarm/media URL to disk
|
|
604
|
-
download-
|
|
603
|
+
download <url> [dest] Stream any Vidfarm/media URL to disk (free — direct media URLs only)
|
|
604
|
+
download-video <url> PAID. Download a video FROM A WEBSITE (YouTube, TikTok, Instagram,
|
|
605
|
+
(aka download-post) X/Twitter, and other supported posts) into durable Vidfarm media.
|
|
606
|
+
Photo/carousel posts come back as an ordered slideshow.
|
|
607
|
+
→ POST /api/v1/primitives/videos/download
|
|
605
608
|
--quality <q> best | hd | full_hd (default: best)
|
|
606
609
|
--no-wait Return the queued job immediately instead of polling
|
|
607
|
-
download-
|
|
610
|
+
download-audio <url> PAID. Download just the AUDIO track (music/voice) from a website post
|
|
611
|
+
(aka download-post-audio) → POST /api/v1/primitives/audio/download
|
|
608
612
|
--no-wait Return the queued job immediately instead of polling
|
|
613
|
+
FREE PLAN: both bill the wallet via a paid resolver. If the user is
|
|
614
|
+
free/no-spend, don't call them — open the URL in Chrome and download
|
|
615
|
+
it from the page, then 'vidfarm put-file ./the-file' to bring it in.
|
|
609
616
|
tasks Cloud Status: imports · forks · renders · jobs → GET /api/v1/user/me/tasks
|
|
610
617
|
--running|--done|--error Filter (or --status <all|running|done|error>); --limit <n>
|
|
611
618
|
wallet Wallet cost log: balance + what each video cost → GET /api/v1/user/me/wallet
|
|
@@ -769,7 +776,10 @@ function loadDotEnvCredentials(cwd = process.cwd()) {
|
|
|
769
776
|
async function main() {
|
|
770
777
|
const argv = process.argv.slice(2);
|
|
771
778
|
loadDotEnvCredentials();
|
|
772
|
-
|
|
779
|
+
// `help` must be caught here too: without it the bare word falls through the
|
|
780
|
+
// dispatch switch and is treated as a TEMPLATE ID by the default `serve` case,
|
|
781
|
+
// which boots a local server on :3000 instead of printing help.
|
|
782
|
+
if (argv.length === 0 || argv[0] === "help" || argv[0] === "--help" || argv[0] === "-h") {
|
|
773
783
|
process.stdout.write(HELP);
|
|
774
784
|
return;
|
|
775
785
|
}
|
|
@@ -952,10 +962,14 @@ async function main() {
|
|
|
952
962
|
case "download":
|
|
953
963
|
await runDownloadCommand(rest);
|
|
954
964
|
return;
|
|
965
|
+
// Aliases: agents look for "download a video from a website", not "post".
|
|
955
966
|
case "download-post":
|
|
967
|
+
case "download-video":
|
|
968
|
+
case "download-url":
|
|
956
969
|
await runDownloadPostCommand(rest);
|
|
957
970
|
return;
|
|
958
971
|
case "download-post-audio":
|
|
972
|
+
case "download-audio":
|
|
959
973
|
await runDownloadPostAudioCommand(rest);
|
|
960
974
|
return;
|
|
961
975
|
case "files":
|
|
@@ -6877,6 +6891,27 @@ async function runDownloadCommand(argv) {
|
|
|
6877
6891
|
console.log(`${GREEN}Downloaded ${formatBytes(bytes)} → ${dest}${RESET}`);
|
|
6878
6892
|
}
|
|
6879
6893
|
}
|
|
6894
|
+
// The FREE fallback for the paid download primitives. Both routes ride a paid
|
|
6895
|
+
// RapidAPI resolver billed to the wallet, so a free-plan customer gets a 402.
|
|
6896
|
+
// Rather than dead-ending them, tell the agent to drive the user's own browser:
|
|
6897
|
+
// open the URL in Chrome and download it from there (no Vidfarm spend).
|
|
6898
|
+
// NOTE: a hoisted function, NOT a module const — `void main()` runs synchronously
|
|
6899
|
+
// until its first await, so a const declared this far down the file is still in
|
|
6900
|
+
// its TDZ when a command handler reads it (same gotcha as the *_HELP consts).
|
|
6901
|
+
function downloadFreeAlternative() {
|
|
6902
|
+
return "open the URL in Chrome and download it from the page yourself ($0.00 — no wallet spend)";
|
|
6903
|
+
}
|
|
6904
|
+
function printDownloadFreePathHint(ctx, kind) {
|
|
6905
|
+
if (ctx.json)
|
|
6906
|
+
return;
|
|
6907
|
+
const noun = kind === "video" ? "video" : "audio";
|
|
6908
|
+
console.log("");
|
|
6909
|
+
console.log(`${YELLOW}Free path (no Vidfarm spend):${RESET} load the URL in Chrome and grab the ${noun} from there.`);
|
|
6910
|
+
console.log(`${DIM} 1. Open the post/page in Chrome (a real browser session handles the login/consent walls).${RESET}`);
|
|
6911
|
+
console.log(`${DIM} 2. Save the ${noun} from the page — right-click → Save, the browser's downloads, or a downloader site.${RESET}`);
|
|
6912
|
+
console.log(`${DIM} 3. Google "youtube ${noun} downloader" or "tiktok/instagram/x ${noun} downloader" if the page won't give it up.${RESET}`);
|
|
6913
|
+
console.log(`${DIM} 4. Then bring the local file into Vidfarm for free: vidfarm put-file ./the-file --folder <folder>${RESET}`);
|
|
6914
|
+
}
|
|
6880
6915
|
async function runDownloadPostCommand(argv) {
|
|
6881
6916
|
const parsed = parseArgs({
|
|
6882
6917
|
args: argv,
|
|
@@ -6891,6 +6926,11 @@ async function runDownloadPostCommand(argv) {
|
|
|
6891
6926
|
throw new Error("download-post --quality must be one of: best, hd, full_hd.");
|
|
6892
6927
|
}
|
|
6893
6928
|
const ctx = commonContext(parsed.values);
|
|
6929
|
+
guardBilled(ctx, {
|
|
6930
|
+
label: "download a video from a website (paid plan — RapidAPI resolver)",
|
|
6931
|
+
estimate: "small per-download wallet charge",
|
|
6932
|
+
freeAlternative: downloadFreeAlternative()
|
|
6933
|
+
});
|
|
6894
6934
|
const tracer = String(parsed.values.tracer ?? `devcli-download-post-${Date.now().toString(36)}`);
|
|
6895
6935
|
const submit = await apiRequest({
|
|
6896
6936
|
method: "POST",
|
|
@@ -6899,6 +6939,9 @@ async function runDownloadPostCommand(argv) {
|
|
|
6899
6939
|
auth: ctx.auth,
|
|
6900
6940
|
body: { tracer, payload: { source_url: url, quality } }
|
|
6901
6941
|
});
|
|
6942
|
+
if (!submit.ok && (submit.status === 402 || submit.status === 401 || submit.status === 403)) {
|
|
6943
|
+
printDownloadFreePathHint(ctx, "video");
|
|
6944
|
+
}
|
|
6902
6945
|
assertApiOk(submit, "download-post");
|
|
6903
6946
|
const jobId = submit.json?.job_id;
|
|
6904
6947
|
if (!jobId || parsed.values["no-wait"]) {
|
|
@@ -6920,6 +6963,11 @@ async function runDownloadPostAudioCommand(argv) {
|
|
|
6920
6963
|
if (!url)
|
|
6921
6964
|
throw new Error("download-post-audio requires a source URL.");
|
|
6922
6965
|
const ctx = commonContext(parsed.values);
|
|
6966
|
+
guardBilled(ctx, {
|
|
6967
|
+
label: "download audio from a website (paid plan — RapidAPI resolver)",
|
|
6968
|
+
estimate: "small per-download wallet charge",
|
|
6969
|
+
freeAlternative: downloadFreeAlternative()
|
|
6970
|
+
});
|
|
6923
6971
|
const tracer = String(parsed.values.tracer ?? `devcli-download-post-audio-${Date.now().toString(36)}`);
|
|
6924
6972
|
const submit = await apiRequest({
|
|
6925
6973
|
method: "POST",
|
|
@@ -6928,6 +6976,9 @@ async function runDownloadPostAudioCommand(argv) {
|
|
|
6928
6976
|
auth: ctx.auth,
|
|
6929
6977
|
body: { tracer, payload: { source_url: url } }
|
|
6930
6978
|
});
|
|
6979
|
+
if (!submit.ok && (submit.status === 402 || submit.status === 401 || submit.status === 403)) {
|
|
6980
|
+
printDownloadFreePathHint(ctx, "audio");
|
|
6981
|
+
}
|
|
6931
6982
|
assertApiOk(submit, "download-post-audio");
|
|
6932
6983
|
const jobId = submit.json?.job_id;
|
|
6933
6984
|
if (!jobId || parsed.values["no-wait"]) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@officexapp/vidfarm-devcli",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.22",
|
|
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": {
|