GuanYixuan / GuanYixuan/pyCapCut
draft_meta_info.json `draft_materials` left empty → CapCut 9.1.0 shows imported media as inaccessible / relink
- Dominant language
- Python
- Stars
- 664
- Forks
- 91
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
Drafts generated by pycapcut leave every group in `draft_meta_info.json` → `draft_materials` **empty**, and the timeline's imported media is never registered there. On **CapCut International 9.1.0 (macOS)**, opening such a draft shows the imported video/audio/image clips as **"file inaccessible" / prompts a relink**, even though the files exist on disk and the `path` fields in `draft_content.json` are correct.
Populating `draft_materials` with the timeline media makes CapCut open the draft with all clips recognized (no relink).
## Root cause
- `DraftFolder.create_draft()` copies a **static** template into the draft folder and never updates it afterwards:
```python
# pycapcut/draft_folder.py (~line 85)
shutil.copy(assets.get_asset_path("DRAFT_META_TEMPLATE"),
os.path.join(draft_path, "draft_meta_info.json"))
```
The template (`pycapcut/assets/draft_meta_info.json`) has all `draft_materials` groups empty:
```json
"draft_materials": [
{"type": 0, "value": []},
{"type": 1, "value": []},
...
]
```
- `ScriptFile.save() → dump(save_path)` only writes `draft_content.json`. Nothing ever writes the imported materials (which the script already knows via `self.materials.videos` / `self.materials.audios`) into `draft_meta_info.json`'s `draft_materials`.
So `draft_content.json` correctly references the media, but the sibling `draft_meta_info.json` "import manifest" stays empty — and CapCut 9.1.0 appears to use that manifest to decide which media has actually been imported.
## Reproduction
```python
import pycapcut as p
df = p.DraftFolder("/path/to/CapCut/.../com.lveditor.draft")
sc = df.create_draft("demo", 1080, 1920, 30, allow_replace=True)
sc.add_segment(p.VideoSegment(p.VideoMaterial("/abs/path/clip.mp4"),
p.Timerange(0, 3_000_000)))
sc.save()
```
Open `demo` in CapCut 9.1.0 → the clip shows as inaccessible / relink prompt.
Inspecting `demo/draft_meta_info.json` → `draft_materials` groups are all `[]`.
## Workaround we currently use (post-save, for reference)
After `save()`, we read the materials back out of `draft_content.json` and write one entry per local video/audio into the `type: 0` group of `draft_meta_info.json`. The entry shape that made CapCut 9.1.0 stop asking for a relink is:
```python
{
"ai_group_type": "", "create_time": -1,
"duration": , # 0 for images
"enter_from": 0, "extra_info": , "file_Path": ,
"height": , "id": , "import_time": -1, "import_time_ms": -1,
"item_source": 1, "material_color_tag": "", "md5": "", "metetype": <"video"|"photo"|"music">,
"roughcut_time_range": {"duration": -1, "start": -1},
"sub_time_range": {"duration": -1, "start": -1},
"type": 0, "width": ,
}
```
This is reverse-engineered from a CapCut-International-9.1.0 hand-authored draft, so it is almost certainly **version-specific** — which is exactly why I'd rather ask than send a blind PR.
## Questions
1. Is populating `draft_meta_info.json` → `draft_materials` at save time meant to be the library's responsibility (i.e. is this a bug), or is it intentionally left to CapCut to backfill on import?
2. What is the correct **`type` grouping** (the template has 0/1/2/3/6/7/8) for each media kind, and the canonical per-entry schema across the CapCut vs 剪映 (JianYing) draft formats? Our workaround crudely dumps all media into `type: 0`, which works for our case but is likely not general.
3. If this is in scope, I'm happy to open a PR that populates the manifest inside `dump()` from `self.materials`. Any guidance on placement / format before I do so would help me get it right.
## Environment
- pycapcut `0.0.3` (behavior unchanged on current `main`)
- CapCut International 9.1.0, macOS
Thanks for the library!
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with pycapcut/draft_folder.py and the ScriptFile.save() → dump(save_path) path, then inspect pycapcut/assets/draft_meta_info.json. Run the provided reproduction and compare draft_content.json with draft_meta_info.json, including the materials in self.materials.videos and self.materials.audios. Done requires an agreed CapCut/JianYing grouping and entry schema, with save-time output that CapCut 9.1.0 recognizes without relinking.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100