Skip to content

load_template + dump silently drops sticker/text/effect segments from existing drafts #71

@Morfeu333

Description

@Morfeu333

Summary

When loading an existing CapCut draft via Script_file.load_template(path), then calling .dump(path) to save modifications, all segments inside sticker, text, and effect tracks are silently dropped. The tracks themselves are preserved (with empty segments: []), but the actual sticker/text/effect content (along with its keyframes, materials, and positioning) is lost.

This caused a destructive data loss in my workflow — I edited an existing draft programmatically and silently deleted manually-placed user stickers/highlights.

Root cause

In pyJianYingDraft/template_mode.py line 218, function import_track():

if track_type.value.allow_modify and imported_materials:
    for segment_data in json_data.get("segments", []):
        # ... handle Video / Audio / other

The allow_modify flag controls whether segments are imported. Looking at track.py:

sticker = Track_meta(Sticker_segment, 14000, False)   # allow_modify=False
text    = Track_meta(Text_segment, 15000, False)      # allow_modify=False
effect  = Track_meta(Effect_segment, 16000, False)    # allow_modify=False

So for these track types, segments are NEVER iterated/imported. The track is created but with segments=[]. When dump() is later called, the empty tracks export back to JSON with no segments — silently overwriting any existing segments that were on disk.

Reproduction

  1. Open CapCut, create a draft with at least one sticker (e.g. Highlight EN Line overlay) with keyframes.
  2. Quit CapCut (so the file is settled on disk).
  3. Run:
from pyJianYingDraft import Script_file
s = Script_file.load_template(draft_info_json_path)
s.dump(draft_info_json_path)   # no other changes
  1. Reopen the draft in CapCut. The sticker track is now empty.

Expected behavior

load_template + dump should be a round-trip preserving operation when no modifications are made. Even for tracks that pyJianYingDraft can't actively edit, segments should be preserved as ImportedSegment (or similar) and round-tripped through dump().

Suggested fix

The else branch already exists in import_track (line 322) for "other types" via ImportedSegment. The issue is the outer condition if track_type.value.allow_modify. Remove that condition (or invert it) so the else branch runs for sticker/text/effect tracks, preserving segments as opaque ImportedSegment objects.

# Inside import_track, after creating track:
for segment_data in json_data.get("segments", []):
    # build common_keyframes (always)
    common_keyframes = build_keyframes_from(segment_data)

    if track_type == Track_type.video:
        # existing video logic, with allow_modify gate
        ...
    elif track_type == Track_type.audio:
        # existing audio logic
        ...
    else:
        # NEW: preserve sticker/text/effect as opaque
        segment = ImportedSegment(segment_data)
        segment.common_keyframes = common_keyframes
        track.segments.append(segment)

ImportedSegment.export_json() should already write back the original dict.

Environment

  • pyJianYingDraft: current main (commit b085f7e)
  • Python 3.13 / macOS 26.1
  • CapCut International 8.5.0

Workaround

Edit the draft_info.json directly with json.load / json.dump instead of using Script_file.load_template + .dump() when the existing draft contains stickers, text, or effects.


Happy to send a PR if the approach above sounds good.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions