Skip to content

Commit bbcb2cd

Browse files
python: thin Python client, published as capcut on PyPI (#125)
capcut.run(cmd, *args, **flags) spawns the CLI once without a shell and returns its JSON; capcut.serve(jobs) feeds the JSONL queue. Pure Python, no dependencies, Python >= 3.9. Not part of the npm tarball.
1 parent dfde2bd commit bbcb2cd

9 files changed

Lines changed: 628 additions & 0 deletions

File tree

‎.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
node_modules/
22
dist/
33
*.bak
4+
5+
# python/ client package build artifacts
6+
python/dist/
7+
python/build/
8+
python/*.egg-info/
9+
__pycache__/

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All notable changes to capcut-cli are documented here. The format follows [Keep
88

99
- `doctor` reports what each draft store holds — for every default CapCut/JianYing project directory it finds (or the one folder named with the new `--drafts <dir>`), a `draft-store` check counts the projects as readable, markerless, encrypted or unreadable. A JianYing 6.0+ store, where every project the app wrote is an encrypted payload, is now named once and up front (warn) with what still works — `init`, `quickstart` and `compile` build plaintext drafts from the bundled template — instead of being discovered one failed command at a time. Same classification as the `template.store` report of `init`/`quickstart`/`compile`. `capcut doctor --drafts <dir>` also makes the check usable on a machine without the app, and in CI.
1010
- `examples/short-video-narration.md` (+ zh-CN) — silent clip → 9:16 draft with a TTS voiceover and script-accurate captions, as four commands (`quickstart --ratio 9:16` → `tts --text-file` → `caption --from-segment --script` → `lint`) and as one script, `examples/scripts/narrate-short.sh`. `examples/scripts/edge-tts-wav.sh` bridges edge-tts (MP3 only) to the WAV `tts` expects at `{out}`; any other engine plugs in through `--tts-cmd`. The vision-model step that writes the script is optional and stays outside the CLI: the script is a text file.
11+
- `python/` — a thin Python client, published to PyPI as `capcut` (`pip install capcut`). `capcut.run(cmd, *args, **flags)` spawns the CLI once without a shell and returns the JSON it prints; keyword arguments become flags (`font_size=16` → `--font-size 16`), positionals pass through as single argv tokens, a non-zero exit raises `CommandError` with `status` and the CLI's JSON. `capcut.serve(jobs)` feeds the stateless JSONL queue and returns one result per job. `capcut.describe()`, `capcut.doctor()`, `capcut.version()`. Pure Python, no dependencies, Python ≥ 3.9; the binary is found on PATH or through `CAPCUT_CLI`. Not part of the npm tarball.
1112

1213
## [0.25.0] — 2026-09-18
1314

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ https://github.com/user-attachments/assets/4e6ee99c-0745-4cfb-8e9b-ad873fb1259b
3232
npm install -g capcut-cli
3333
```
3434

35+
From Python: `pip install capcut` wraps the same binary — `capcut.run("quickstart", "my-short", video="clip.mp4", ratio="9:16")` — see [python/README.md](https://github.com/renezander030/capcut-cli/blob/master/python/README.md).
36+
3537
```bash
3638
capcut doctor
3739
capcut quickstart my-first --video clip.mp4 --srt captions.srt

‎README.zh-CN.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ https://github.com/user-attachments/assets/4e6ee99c-0745-4cfb-8e9b-ad873fb1259b
3030
npm install -g capcut-cli
3131
```
3232

33+
在 Python 里用:`pip install capcut` 封装同一个命令行 —— `capcut.run("quickstart", "我的短视频", video="clip.mp4", ratio="9:16")`,见 [python/README.md](https://github.com/renezander030/capcut-cli/blob/master/python/README.md)。
34+
3335
```bash
3436
capcut doctor
3537
capcut quickstart my-first --video clip.mp4 --srt captions.srt

‎python/README.md‎

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# capcut(Python 客户端) · capcut (Python client)
2+
3+
中文 | [English](#english)
4+
5+
用 Python 创建和编辑 CapCut / 剪映草稿。这是 [capcut-cli](https://github.com/renezander030/capcut-cli) 的一层薄封装:每次调用启动一次 `capcut` 命令,不经过 shell,返回它打印的那一份 JSON。没有服务、没有守护进程,磁盘上的草稿就是全部状态。打开剪映时,每一轨都还是可编辑的。
6+
7+
## 安装
8+
9+
```bash
10+
npm install -g capcut-cli # 命令行本体,需要 Node ≥ 18
11+
pip install capcut # 本包,纯 Python,无依赖
12+
capcut doctor # 检查环境
13+
```
14+
15+
## 五行起步
16+
17+
```python
18+
import capcut
19+
20+
d = capcut.run("quickstart", "旁白短视频", video="clip.mp4", ratio="9:16")
21+
capcut.run("add-text", d["draft_path"], "0s", "3s", "你好,世界", font_size=16)
22+
print(capcut.run("lint", d["draft_path"])["summary"])
23+
```
24+
25+
- **关键字参数就是命令行选项**:`font_size=16` → `--font-size 16`,`karaoke=True` → `--karaoke`,列表会重复该选项,`None` / `False` 直接省略。
26+
- **位置参数原样传递**,每个参数就是一个 argv,中文、空格、引号都不需要转义。
27+
- 全部命令、参数和选项见[命令参考(中文)](https://github.com/renezander030/capcut-cli/blob/master/docs/command-reference.zh-CN.md),或者在 Python 里 `capcut.describe()`。
28+
29+
## 出错时
30+
31+
命令非零退出会抛出 `capcut.CommandError`,带 `status`、`data`(CLI 打印的 JSON,通常含 `error`)、`stdout`、`stderr`:
32+
33+
```python
34+
try:
35+
capcut.run("lint", path)
36+
except capcut.CommandError as e:
37+
print(e.status, e.data) # lint 有错误时退出码为 2
38+
```
39+
40+
不想抛异常就用 `capcut.run_raw(...)`,它返回 `Result`(`ok`、`status`、`data`、`error`)。找不到 `capcut` 命令时抛 `capcut.CliNotFound`,提示里有安装命令;也可以用环境变量 `CAPCUT_CLI` 指定,例如 `CAPCUT_CLI="node /path/to/capcut-cli/dist/index.js"`。
41+
42+
## 批量:`serve`
43+
44+
`capcut serve` 是一个无状态的 JSONL 任务队列。从 Python 喂任务进去,拿回每个任务一条结果:
45+
46+
```python
47+
results = capcut.serve([
48+
capcut.Job("add-text", project=path, args=["8s", "2s", "关注我"], id="title"),
49+
capcut.Job("lint", project=path),
50+
], workers=2)
51+
for r in results:
52+
print(r["id"], r["ok"], r["status"], r["stdout"])
53+
```
54+
55+
失败的任务是一条 `ok: false` 的结果,不是异常。
56+
57+
## 剪映 6.0+ 用户
58+
59+
新建的草稿是明文,据报告剪映 11.4(macOS)能打开并就地升级,其他版本未验证;已有的加密草稿本 CLI 不读取。`capcut.doctor()` 会报告环境,`capcut.run("decrypt", path)` 会报告某个草稿的加密状态;来龙去脉见 [jianying-encryption.zh-CN.md](https://github.com/renezander030/capcut-cli/blob/master/docs/jianying-encryption.zh-CN.md)。
60+
61+
---
62+
63+
## English
64+
65+
Create and edit CapCut / JianYing drafts from Python. A thin layer over [capcut-cli](https://github.com/renezander030/capcut-cli): each call spawns the `capcut` binary once, without a shell, and returns the one JSON document it prints. No server, no daemon; the draft on disk is the only state, and every track stays editable in the app.
66+
67+
### Install
68+
69+
```bash
70+
npm install -g capcut-cli # the CLI itself, Node >= 18
71+
pip install capcut # this package, pure Python, no dependencies
72+
capcut doctor # environment check
73+
```
74+
75+
### Five lines
76+
77+
```python
78+
import capcut
79+
80+
d = capcut.run("quickstart", "Narrated short", video="clip.mp4", ratio="9:16")
81+
capcut.run("add-text", d["draft_path"], "0s", "3s", "Hello, world", font_size=16)
82+
print(capcut.run("lint", d["draft_path"])["summary"])
83+
```
84+
85+
- **Keyword arguments are flags**: `font_size=16` → `--font-size 16`, `karaoke=True` → `--karaoke`, a list repeats the flag, `None` / `False` are dropped.
86+
- **Positional arguments pass through as they are**, one argv token each: text with spaces or quotes never needs escaping.
87+
- Every command, argument and option: [command reference](https://github.com/renezander030/capcut-cli/blob/master/docs/command-reference.md), or `capcut.describe()` from Python.
88+
89+
### Errors
90+
91+
A non-zero exit raises `capcut.CommandError` with `status`, `data` (the CLI's JSON, usually with `error`), `stdout`, `stderr`:
92+
93+
```python
94+
try:
95+
capcut.run("lint", path)
96+
except capcut.CommandError as e:
97+
print(e.status, e.data) # lint exits 2 on errors
98+
```
99+
100+
`capcut.run_raw(...)` never raises; it returns a `Result` (`ok`, `status`, `data`, `error`). A missing binary raises `capcut.CliNotFound` with the install line; `CAPCUT_CLI` can point at one explicitly, e.g. `CAPCUT_CLI="node /path/to/capcut-cli/dist/index.js"`.
101+
102+
### Batch: `serve`
103+
104+
`capcut serve` is a stateless JSONL job queue. Feed it jobs from Python and get one result per job:
105+
106+
```python
107+
results = capcut.serve([
108+
capcut.Job("add-text", project=path, args=["8s", "2s", "Subscribe"], id="title"),
109+
capcut.Job("lint", project=path),
110+
], workers=2)
111+
for r in results:
112+
print(r["id"], r["ok"], r["status"], r["stdout"])
113+
```
114+
115+
A failed job is a result with `ok: false`, not an exception.
116+
117+
### Development
118+
119+
```bash
120+
cd python && python -m unittest discover -s tests -v
121+
python -m build
122+
```
123+
124+
MIT, same as capcut-cli.

0 commit comments

Comments
 (0)