Metadata-Version: 2.4
Name: capcut
Version: 0.1.3
Summary: Python client for capcut-cli: create and edit CapCut / JianYing (剪映) drafts from Python. JSON in, JSON out, no server.
Author: Rene Zander
License: MIT
Project-URL: Homepage, https://github.com/renezander030/capcut-cli
Project-URL: Documentation, https://github.com/renezander030/capcut-cli/blob/master/python/README.md
Project-URL: Changelog, https://github.com/renezander030/capcut-cli/blob/master/CHANGELOG.md
Project-URL: Issues, https://github.com/renezander030/capcut-cli/issues
Keywords: capcut,jianying,剪映,video,draft,cli,automation,short-video
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# capcut（Python 客户端） · capcut (Python client)

中文 | [English](#english)

用 Python 创建和编辑 CapCut / 剪映草稿。这是 [capcut-cli](https://github.com/renezander030/capcut-cli) 的一层薄封装：每次调用启动一次 `capcut` 命令，不经过 shell，返回它打印的那一份 JSON。没有服务、没有守护进程，磁盘上的草稿就是全部状态。打开剪映时，每一轨都还是可编辑的。

## 安装

```bash
npm install -g capcut-cli   # 命令行本体，需要 Node ≥ 18
pip install capcut          # 本包，纯 Python，无依赖
capcut doctor               # 检查环境
```

## 五行起步

```python
import capcut

d = capcut.run("quickstart", "旁白短视频", video="clip.mp4", ratio="9:16")
capcut.run("add-text", d["draft_path"], "0s", "3s", "你好，世界", font_size=16)
print(capcut.run("lint", d["draft_path"])["summary"])
```

- **关键字参数就是命令行选项**：`font_size=16` → `--font-size 16`，`karaoke=True` → `--karaoke`，列表会重复该选项，`None` / `False` 直接省略。
- **位置参数原样传递**，每个参数就是一个 argv，中文、空格、引号都不需要转义。
- 全部命令、参数和选项见[命令参考（中文）](https://github.com/renezander030/capcut-cli/blob/master/docs/command-reference.zh-CN.md)，或者在 Python 里 `capcut.describe()`。使用 `capcut.describe(compact=True)` 获取精简索引，`capcut.describe(command="compile")` 获取单个命令的完整契约（命令行需要 v0.28.0 或更新版本）。

## 出错时

命令非零退出会抛出 `capcut.CommandError`，带 `status`、`data`（CLI 打印的 JSON，通常含 `error`）、`stdout`、`stderr`：

```python
try:
    capcut.run("lint", path)
except capcut.CommandError as e:
    print(e.status, e.data)          # lint 有错误时退出码为 2
```

不想抛异常就用 `capcut.run_raw(...)`，它返回 `Result`（`ok`、`status`、`data`、`error`）。找不到 `capcut` 命令时抛 `capcut.CliNotFound`，提示里有安装命令；也可以用环境变量 `CAPCUT_CLI` 指定，例如 `CAPCUT_CLI="node /path/to/capcut-cli/dist/index.js"`。

Windows 上的 `CAPCUT_CLI` 使用双引号包住带空格的路径（不是 POSIX 单引号）。例如在 PowerShell 中：

```powershell
$env:CAPCUT_CLI = '"C:\Program Files\nodejs\node.exe" "C:\CapCut Tools\dist\index.js"'
```

## 批量：`serve`

`capcut serve` 是一个无状态的 JSONL 任务队列。从 Python 喂任务进去，拿回每个任务一条结果：

```python
results = capcut.serve([
    capcut.Job("add-text", project=path, args=["8s", "2s", "关注我"], id="title"),
    capcut.Job("lint", project=path),
], workers=2)
for r in results:
    print(r["id"], r["ok"], r["status"], r["stdout"])
```

失败的任务是一条 `ok: false` 的结果，不是异常。

## 剪映 6.0+ 用户

新建的草稿是明文，据报告剪映 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)。

## 反馈与商业合作

- 在用 Python 驱动 CapCut / 剪映？到 [这个讨论](https://github.com/renezander030/capcut-cli/discussions/131) 说说你在做什么，这决定 Python 客户端下一步做什么。
- 与赞助无关：如果你正在把 capcut 集成进自己的产品，或者需要它实现目前还不支持的功能，我会承接少量集成项目。请发邮件至 rene@renezander.com，写明你在做什么。
- 想支持这个项目：[成为赞助者](https://github.com/sponsors/renezander030)。

---

## English

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.

### Install

```bash
npm install -g capcut-cli   # the CLI itself, Node >= 18
pip install capcut          # this package, pure Python, no dependencies
capcut doctor               # environment check
```

### Five lines

```python
import capcut

d = capcut.run("quickstart", "Narrated short", video="clip.mp4", ratio="9:16")
capcut.run("add-text", d["draft_path"], "0s", "3s", "Hello, world", font_size=16)
print(capcut.run("lint", d["draft_path"])["summary"])
```

- **Keyword arguments are flags**: `font_size=16` → `--font-size 16`, `karaoke=True` → `--karaoke`, a list repeats the flag, `None` / `False` are dropped.
- **Positional arguments pass through as they are**, one argv token each: text with spaces or quotes never needs escaping.
- Every command, argument and option: [command reference](https://github.com/renezander030/capcut-cli/blob/master/docs/command-reference.md), or `capcut.describe()` from Python. Use `capcut.describe(compact=True)` for the small discovery index and `capcut.describe(command="compile")` for a complete command contract (requires CLI v0.28.0 or newer). A list selects several names.

### Errors

A non-zero exit raises `capcut.CommandError` with `status`, `data` (the CLI's JSON, usually with `error`), `stdout`, `stderr`:

```python
try:
    capcut.run("lint", path)
except capcut.CommandError as e:
    print(e.status, e.data)          # lint exits 2 on errors
```

`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"`.

On Windows, quote paths with double quotes inside `CAPCUT_CLI`. For example in PowerShell:

```powershell
$env:CAPCUT_CLI = '"C:\Program Files\nodejs\node.exe" "C:\CapCut Tools\dist\index.js"'
```

When setting the variable from Python, `subprocess.list2cmdline([node_path, cli_path])` builds Windows quoting; `shlex.join(...)` is for POSIX. Command arguments are passed directly to the child process without shell expansion.

### Batch: `serve`

`capcut serve` is a stateless JSONL job queue. Feed it jobs from Python and get one result per job:

```python
results = capcut.serve([
    capcut.Job("add-text", project=path, args=["8s", "2s", "Subscribe"], id="title"),
    capcut.Job("lint", project=path),
], workers=2)
for r in results:
    print(r["id"], r["ok"], r["status"], r["stdout"])
```

A failed job is a result with `ok: false`, not an exception.

### Feedback and commercial work

- Driving CapCut or JianYing from Python? Tell us what you are building in [this discussion](https://github.com/renezander030/capcut-cli/discussions/131); it decides what the Python client gets next.
- Separate from sponsorship: if you are building capcut into a product, or you need it to do something it does not do yet, I take on a small number of integration engagements. Write to rene@renezander.com and say what you are building.
- To support the project: [become a sponsor](https://github.com/sponsors/renezander030).

### Development

```bash
cd python && python -m unittest discover -s tests -v
python -m build
```

MIT, same as capcut-cli.
