Full Code of xiaoyiv/JianYingProDraft for AI

main 76feb5881e49 cached
13 files
25.3 KB
7.2k tokens
40 symbols
1 requests
Download .txt
Repository: xiaoyiv/JianYingProDraft
Branch: main
Commit: 76feb5881e49
Files: 13
Total size: 25.3 KB

Directory structure:
gitextract_e1k8nue9/

├── .gitignore
├── README.md
├── draft/
│   ├── Draft.py
│   ├── __init__.py
│   ├── material.py
│   ├── template.py
│   ├── track.py
│   └── util.py
├── main.py
├── project.py
├── template json/
│   ├── draft_content.json
│   └── draft_meta_info.json
└── test.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
__pycache__

================================================
FILE: README.md
================================================
# JianYingProDraft

## 说明

1. 实现原理 : `JianYingPro` 项目文件是 `json` 的形式存储的,只需要创建`draft_content.json`,`draft_mate_info.json` 打开软件后会自动补全。
2. 添加一个媒体到轨道顺序 `草稿媒体库` -> `内容媒体库`-> `轨道片段`
3. `add_media_to_track` 会识别媒体类型,加入到对应轨道。
4. 当没有视频轨道时,创建音频轨道会先创建视频轨道。

```python
if __name__ == "__main__":
    # 新建草稿
    draft = Draft("测试草稿") 
    # 将媒体转化为草稿素材
    audio = Material("D:/Music/Krubb Wenkroist - Bleach.mp3")
    # 将媒体添加到轨道中
    draft.add_media_to_track(audio)
    draft.add_media_to_track('D:/Videos/剪印导出/测试1(1).mp4')
    # 保存草稿
    draft.save()
```

使用前先修改`main.py`中的草稿文件夹路径

```python
drafts_folder = "D:/JianyingPro Drafts"
```


================================================
FILE: draft/Draft.py
================================================


================================================
FILE: draft/__init__.py
================================================
import os
import time
import util
import template
from material import Material
from track import Tracks

class Draft:

    drafts_folder = "D:/JianyingPro Drafts"
    template_folder = "./template json/"
    content_file = "draft_content.json"
    meta_info_file = "draft_meta_info.json"

    def __init__(self, name:str="Test"):
        # 路径变量
        self.name = name
        self.folder = os.path.join(self.drafts_folder, name)
        self.content_path = os.path.join(self.folder, self.content_file)
        self.meta_info_path = os.path.join(self.folder, self.meta_info_file)
        # 新建项目文件夹
        util.new_folder(self.folder)
        # 读取草稿模板
        self.content = util.read_json(os.path.join(self.template_folder,self.content_file))
        self.meta_info = util.read_json(os.path.join(self.template_folder,self.meta_info_file))
        # 初始化草稿内容信息
        self.content['id'] = util.generate_id()
        # 初始化素材信息
        self.meta_info['id'] = util.generate_id()
        self.meta_info['draft_fold_path'] = self.folder.replace("\\",'/')
        self.meta_info['draft_timeline_metetyperials_size_'] = 0
        self.meta_info['tm_draft_create'] = time.time()
        self.meta_info['tm_draft_modified'] = time.time()
        self.meta_info['draft_root_path'] = self.drafts_folder.replace("/","\\")
        self.meta_info['draft_removable_storage_device'] = self.drafts_folder.split(':/')[0]
        # 创建变量
        self.draft_materials:list = self.meta_info['draft_materials'][0]['value'] # 草稿素材库
        self.content_materials:list = self.content['materials'] # 内容素材库
        self.tracks = Tracks() # 轨道
        self.materials = {}

    def _medai_tpye(self,media):
        if type(media) == str:
            # 当media为文件路径时
            if os.path.exists(media):
                return 'path'
            else:
                # 文件不存在
                return 'text'
        else:
            return media

    def add_media_to_materials(self,file):
        """
            添加媒体到素材库

            如果是DraftMaterial类直接添加到素材库

            如果是文件路径先转化为DraftMaterial
        """
        if type(file) == Material:
            self.materials[file.file_Path] = file
            self.draft_materials.append(file.data)
            return file
        if file not in self.materials:
            mate = Material(file)
            self.materials[file] = mate
            self.draft_materials.append(mate.data)
            return mate
        else:
            return self.materials[file]

    def _content_material(self,material:Material):
        materials = {}
        extra_material_refs = []
        if material.metetype == 'video':
            materials['speeds']=template.speed()
            materials['sound_channel_mappings']=template.sound_channel_mapping()
            materials['canvases']=template.canvase()
        elif material.metetype == 'photo':
            pass
        elif material.metetype == 'audio':
            materials['speeds']=template.speed()
            materials['sound_channel_mappings']=template.sound_channel_mapping()
            materials['beats']=template.sound_channel_mapping()
        elif material.metetype == 'text':
            materials['material_animations']=template.material_animation()

        materials[f'{material.track_type}s'] = material.content_material
        
        for key in materials:
            extra_material_refs.append(materials[key]['id'])
        return materials,extra_material_refs,material.content_material['id']

    def add_media_to_track(self,media,start=0,duration=0,index=0):
        if duration==0:
            duration = media.duration

        segment = template.segment()
        track = []

        if type(media) == str:
            media = Material(media)

        if media.metetype == 'video':
            track = self.tracks.add_video_track(index)
        elif media.metetype == 'photo':
            track = self.tracks.add_video_track(index)
        elif media.metetype == 'audio':
            track = self.tracks.add_audio_track(index)
        elif media.metetype == 'text':
            track = self.tracks.add_text_track(index)

        # 轨道总时长
        track_duration = 0
        if len(track['segments']) != 0:
            track_duration = track['segments'][-1]['target_timerange']['duration'] + track['segments'][-1]['target_timerange']['start']

        materials,extra_material_refs,material_id = self._content_material(media)
        for key in materials:
            self.content_materials[key].append(materials[key])

        segment['extra_material_refs'] = extra_material_refs
        segment['material_id'] = material_id
        segment['source_timerange'] = { "duration": duration, "start": start }
        segment['target_timerange'] = { "duration": duration, "start": track_duration }
        
        self.tracks.to_track(media.metetype,segment,index)

    def save(self):
        """保存草稿"""
        self.content['tracks'] = self.tracks._composite() # 覆盖轨道
        util.write_json(self.content_path,self.content)
        util.write_json(self.meta_info_path,self.meta_info)

if __name__ == "__main__":
    # 新建项目
    draft = Draft("草稿")
    text = Material('Hello World')
    text.change_color('#ABCABC')
    draft.add_media_to_track(text,duration=3000000)
    draft.save()

================================================
FILE: draft/material.py
================================================
import template
import os
from pymediainfo import MediaInfo

class Material:

    media_type_mapping = {
        "video": "video",
        "audio": "music"
    }

    def __init__(self, file) -> None:
        self._data = template.material()
        self.metetype = ''
        self.track_type = ''
        self.width = 0
        self.height = 0
        self.duration = 0
        self.extra_info = ''
        self.file_Path = ''
        self.id = self._data['id']
        self.content_material = {}

        if type(file) == str:
            if os.path.exists(file):
                self.to_material(file)
                if self.track_type == 'video':
                    self.content_material = self.video()
                elif self.track_type == 'audio':
                    self.content_material =self.audio()
            else:
                self.metetype = 'text'
                self.track_type = 'text'
                self.content_material = self.text()
                self.content_material['content'] = self.content_material['content'].replace('默认文本',file)
        elif type(file) == dict:
            # 估计用不到
            self.load_material(file)
        else:
            pass # 素材类型错误

    @property
    def data(self):
        self._data['metetype'] = self.metetype
        self._data['width'] = self.width
        self._data['height'] = self.height
        self._data['duration'] = self.duration
        self._data['extra_info'] = self.extra_info
        self._data['file_Path'] = self.file_Path
        return self._data
    
    @data.setter
    def data(self, value):
        self._data = value

    def to_material(self,file_path):
        """
            通过文件的方式去加载为素材
        """
        media_info = MediaInfo.parse(file_path).to_data()["tracks"][1]
        self.track_type = media_info['track_type'].lower()
        self.metetype = self.media_type_mapping[self.track_type]
        if  "width" in media_info:
            self.width = media_info['width']
            self.height = media_info['height']
        self.duration = media_info['duration']*1000
        self.extra_info= file_path.split("/")[-1]
        self.file_Path = file_path

    def load_material(self,material):
        """
            将剪映的素材加载为素材类
        """
        self.metetype =material['metetype']
        self.width = material['width']
        self.height = material['height']
        self.duration = material['duration']
        self.extra_info = material['extra_info']
        self.file_Path =material['file_Path']
        self.id = material['id']

    def video(self):
        v = template.video()
        v["duration"]= self.duration
        v["height"]= self.height
        v["local_material_id"]= self.id
        v["material_name"]=  self.extra_info
        v["path"]=  self.file_Path
        v["type"]=  self.metetype
        v["width"]=  self.width
        return v
    
    def audio(self):
        a = template.audio()
        a["duration"]= self.duration
        a["local_material_id"]= self.id        
        a["name"]=  self.extra_info
        a["path"]=  self.file_Path
        a["type"]=  "extract_" + self.metetype
        return a
    
    def text(self):
        t = template.text()
        return t

    def change_color(self,hex):
        self.content_material['text_color'] = hex
        r = int(hex[1:3],16)
        g = int(hex[3:5],16)
        b = int(hex[5:7],16)
        color1 = "<color=(1.000000, 1.000000, 1.000000, 1.000000)>"
        color2 = F'<color=({round(r/255,6):.6f}, {round(g/255,6):.6f}, {round(b/255,6):.6f}, 1.000000)>' 
        self.content_material['content'] = self.content_material['content'].replace(color1,color2)

================================================
FILE: draft/template.py
================================================
import time
import util

def canvase():
    return {
        "album_image": "",
        "blur": 0.0,
        "color": "",
        "id": util.generate_id(),
        "image": "",
        "image_id": "",
        "image_name": "",
        "source_platform": 0,
        "team_id": "",
        "type": "canvas_color"
    }

def sound_channel_mapping():
    return {
        "audio_channel_mapping": 0,
        "id":  util.generate_id(),
        "is_config_open": False,
        "type": "none"
    }

def speed():
    return {
        "curve_speed": None,
        "id": util.generate_id(),
        "mode": 0,
        "speed": 1.0,
        "type": "speed"
    }

def video():
    return {
            "audio_fade": None,
            "cartoon_path": "",
            "category_id": "",
            "category_name": "local",
            "check_flag": 63487,
            "crop": {
            "lower_left_x": 0.0,
            "lower_left_y": 1.0,
            "lower_right_x": 1.0,
            "lower_right_y": 1.0,
            "upper_left_x": 0.0,
            "upper_left_y": 0.0,
            "upper_right_x": 1.0,
            "upper_right_y": 0.0
            },
            "crop_ratio": "free",
            "crop_scale": 1.0,
            "duration": 0,
            "extra_type_option": 0,
            "formula_id": "",
            "freeze": None,
            "gameplay": None,
            "has_audio": True,
            "height": 0,
            "id": util.generate_id(),
            "intensifies_audio_path": "",
            "intensifies_path": "",
            "is_unified_beauty_mode": False,
            "local_id": "",
            "local_material_id":"",
            "material_id": "",
            "material_name": "",
            "material_url": "",
            "matting": {
            "flag": 0,
            "has_use_quick_brush": False,
            "has_use_quick_eraser": False,
            "interactiveTime": [],
            "path": "",
            "strokes": []
            },
            "media_path": "",
            "object_locked": None,
            "path": "",
            "picture_from": "none",
            "picture_set_category_id": "",
            "picture_set_category_name": "",
            "request_id": "",
            "reverse_intensifies_path": "",
            "reverse_path": "",
            "source_platform": 0,
            "stable": None,
            "team_id": "",
            "type":"",
            "video_algorithm": {
            "algorithms": [],
            "deflicker": None,
            "motion_blur_config": None,
            "noise_reduction": None,
            "path": "",
            "time_range": None
            },
            "width": 0
        }

def material():
    return {
        "create_time": int(time.time()),
        "duration": 0,
        "extra_info": "",
        "file_Path": "",
        "height": 0,
        "id": util.generate_id(),
        "import_time": int(time.time()),
        "import_time_ms":  int(time.time())*10^6,
        "md5": "",
        "metetype": "",
        "roughcut_time_range": { "duration": 0, "start": 0 },
        "sub_time_range": { "duration": -1, "start": -1 },
        "type": 0,
        "width": 0
    }

def track():
    return {
      "attribute": 0,
      "flag": 0,
      "id": util.generate_id(),
      "segments":[],
      "type": ""
    }

def segment():
    return {
          "cartoon": False,
          "clip": {
            "alpha": 1.0,
            "flip": { "horizontal": False, "vertical": False },
            "rotation": 0.0,
            "scale": { "x": 1.0, "y": 1.0 },
            "transform": { "x": 0.0, "y": 0.0 }
          },
          "common_keyframes": [],
          "enable_adjust": True,
          "enable_color_curves": True,
          "enable_color_wheels": True,
          "enable_lut": True,
          "enable_smart_color_adjust": False,
          "extra_material_refs": [
          ],
          "group_id": "",
          "hdr_settings": { "intensity": 1.0, "mode": 1, "nits": 1000 },
          "id": util.generate_id(),
          "intensifies_audio": False,
          "is_placeholder": False,
          "is_tone_modify": False,
          "keyframe_refs": [],
          "last_nonzero_volume": 1.0,
          "material_id":"",
          "render_index": 0,
          "reverse": False,
          "source_timerange": { "duration": 0, "start": 0 },
          "speed": 1.0,
          "target_timerange": { "duration": 0, "start": 0 },
          "template_id": "",
          "template_scene": "default",
          "track_attribute": 0,
          "track_render_index": 0,
          "visible": True,
          "volume": 1.0
        }

def beat():
    return {
        "ai_beats": {
          "beats_path": "",
          "beats_url": "",
          "melody_path": "",
          "melody_percents": [0.0],
          "melody_url": ""
        },
        "enable_ai_beats": False,
        "gear": 404,
        "id": util.generate_id(),
        "mode": 404,
        "type": "beats",
        "user_beats": [],
        "user_delete_ai_beats": None
      }

def audio():
    return {
        "app_id": 0,
        "category_id": "",
        "category_name": "local",
        "check_flag": 1,
        "duration": 0,
        "effect_id": "",
        "formula_id": "",
        "id": util.generate_id(),
        "intensifies_path": "",
        "local_material_id": "",
        "music_id": util.generate_id(),
        "name": "Krubb Wenkroist - Bleach.mp3",
        "path": "D:/Music/Krubb Wenkroist - Bleach.mp3",
        "request_id": "",
        "resource_id": "",
        "source_platform": 0,
        "team_id": "",
        "text_id": "",
        "tone_category_id": "",
        "tone_category_name": "",
        "tone_effect_id": "",
        "tone_effect_name": "",
        "tone_speaker": "",
        "tone_type": "",
        "type": "extract_music",
        "video_id": "",
        "wave_points": []
      }

def text():
    return {
        "add_type": 0,
        "alignment": 1,
        "background_alpha": 1.0,
        "background_color": "",
        "background_height": 1.0,
        "background_horizontal_offset": 0.0,
        "background_round_radius": 0.0,
        "background_style": 0,
        "background_vertical_offset": 0.0,
        "background_width": 1.0,
        "bold_width": 0.0,
        "border_color": "",
        "border_width": 0.08,
        "check_flag": 7,
        "content": "<font id=\"\" path=\"E:/JianyingPro/4.2.0.10100/Resources/Font/SystemFont/zh-hans.ttf\"><color=(1.000000, 1.000000, 1.000000, 1.000000)><size=15.000000>[默认文本]</size></color></font>",
        "font_category_id": "",
        "font_category_name": "",
        "font_id": "",
        "font_name": "",
        "font_path": "E:/JianyingPro/4.2.0.10100/Resources/Font/SystemFont/zh-hans.ttf",
        "font_resource_id": "",
        "font_size": 15.0,
        "font_source_platform": 0,
        "font_team_id": "",
        "font_title": "none",
        "font_url": "",
        "fonts": [],
        "force_apply_line_max_width": False,
        "global_alpha": 1.0,
        "group_id": "",
        "has_shadow": False,
        "id": util.generate_id(),
        "initial_scale": 1.0,
        "is_rich_text": False,
        "italic_degree": 0,
        "ktv_color": "",
        "language": "",
        "layer_weight": 1,
        "letter_spacing": 0.0,
        "line_spacing": 0.02,
        "name": "",
        "preset_category": "",
        "preset_category_id": "",
        "preset_has_set_alignment": False,
        "preset_id": "",
        "preset_index": 0,
        "preset_name": "",
        "recognize_type": 0,
        "relevance_segment": [],
        "shadow_alpha": 0.8,
        "shadow_angle": -45.0,
        "shadow_color": "",
        "shadow_distance": 8.0,
        "shadow_point": { "x": 1.0182337649086284, "y": -1.0182337649086284 },
        "shadow_smoothing": 1.0,
        "shape_clip_x": False,
        "shape_clip_y": False,
        "style_name": "",
        "sub_type": 0,
        "text_alpha": 1.0,
        "text_color": "#FFFFFF",
        "text_preset_resource_id": "",
        "text_size": 30,
        "text_to_audio_ids": [],
        "tts_auto_update": False,
        "type": "text",
        "typesetting": 0,
        "underline": False,
        "underline_offset": 0.22,
        "underline_width": 0.05,
        "use_effect_default_color": True,
        "words": []
      }

def material_animation():
    return {
        "animations": [],
        "id": util.generate_id(),
        "type": "sticker_animation"
    }



================================================
FILE: draft/track.py
================================================
import template

class Tracks:

    def __init__(self) -> None:
        """初始化轨道类型

        Args:
            tracks (list, optional): 轨道. Defaults to [].
        """
        self.video_track = []
        self.audio_track = []
        self.text_track = []
        
    def add_video_track(self,track_index=0):
        """
        添加一条视频轨道
        当track_index超过现有轨道数时,则新建轨道,否则为选取轨道    
        Args:
            track_index (int, optional): 第几条轨道. Defaults to 0.

        Returns:
            dict: 返回轨道字典
        """
        track = self._add_track(self.video_track,'video',track_index)
        if track:
            self.video_track.append(track)
        return self.video_track[track_index]
    
    def add_audio_track(self,track_index=0):
        track = self._add_track(self.audio_track,'audio',track_index)
        if track:
            # 当视频轨道为空时
            if len(self.video_track) == 0 :
                self.add_video_track()
            self.audio_track.append(track)
        return self.audio_track[track_index]

    def add_text_track(self,track_index=0):
        track = self._add_track(self.text_track,'text',track_index)
        if track:
            # 当视频轨道为空时
            if len(self.video_track) == 0 :
                self.add_video_track()
            self.text_track.append(track)
        return self.text_track[track_index]

    def _add_track(self,tracks,track_type,track_index):
        track_len = len(tracks)
        if track_index == track_len:
            track = template.track()
            track['type'] = track_type
            if track_len:
                track['flag'] = 2
            return track
        else:
            return False

    def to_track(self,metetype,segment,track_index):
        if metetype == "video":
            self.video_track[track_index]['segments'].append(segment)
        elif metetype == "music":
            self.audio_track[track_index]['segments'].append(segment)
        elif metetype == "text":
            self.text_track[track_index]['segments'].append(segment)

    def _composite(self):
        """
            将所有轨道合成为一个列表
        """
        track = []
        track.extend(self.video_track)
        track.extend(self.text_track)
        track.extend(self.audio_track)
        return track
    

================================================
FILE: draft/util.py
================================================
import os
import shutil
import uuid
import json

def generate_id():
    """
        生成uuid
    """
    return str(uuid.uuid4()).upper()

def write_json(path,data):
    with open(path,'w') as file:
        json.dump(data,file)

def read_json(path):
    with open(path,'r') as file:
        return json.load(file)

def new_folder(folder_path):
    if os.path.exists(folder_path):
        for filename in os.listdir(folder_path):
            file_path = os.path.join(folder_path, filename)
            if os.path.isfile(file_path):
                os.remove(file_path)
            elif os.path.isdir(file_path):
                shutil.rmtree(file_path)
    else:
        os.mkdir(folder_path)


================================================
FILE: main.py
================================================


================================================
FILE: project.py
================================================
import random
import os
import selenium
from draft import Draft
from draft import Material

# 新建项目
draft = Draft("测试草稿")
# 选择背景音乐并添加鼓点
audio = "D:/Music/Krubb Wenkroist - Bleach.mp3"
draft.add_media_to_track(audio)
# 读取鼓点
beats = draft.content_materials['beats'][0]['user_beats']
# 加载视频
files= []
for pt in os.listdir('D:/myCode/Python/spider/douyin_spider/media/video/小仙儿'):
    file_path = os.path.join('D:/myCode/Python/spider/douyin_spider/media/video/小仙儿',pt)
    files.append(file_path)
# 随机裁切视频为合适时长
end = 0
for beat in beats:
    duration = beat - end
    mate = Material(files[random.randint(0,len(files)-1)])
    start = int(random.uniform(0,(mate.duration-duration)/1000))*1000
    Draft.add_media_to_track(mate,start,duration)
    end = beat
# 保存草稿
draft.save()

================================================
FILE: template json/draft_content.json
================================================
{
  "canvas_config": { "height": 1080, "ratio": "original", "width": 1920 },
  "color_space": -1,
  "config": {
    "adjust_max_index": 1,
    "attachment_info": [],
    "combination_max_index": 1,
    "export_range": null,
    "extract_audio_last_index": 1,
    "lyrics_recognition_id": "",
    "lyrics_sync": true,
    "lyrics_taskinfo": [],
    "maintrack_adsorb": true,
    "material_save_mode": 0,
    "original_sound_last_index": 1,
    "record_audio_last_index": 1,
    "sticker_max_index": 1,
    "subtitle_recognition_id": "",
    "subtitle_sync": true,
    "subtitle_taskinfo": [],
    "system_font_list": [],
    "video_mute": false,
    "zoom_info_params": null
  },
  "cover": null,
  "create_time": 0,
  "duration": 0,
  "extra_info": null,
  "fps": 30.0,
  "free_render_index_mode_on": false,
  "group_container": null,
  "id": "",
  "keyframe_graph_list": [],
  "keyframes": {
    "adjusts": [],
    "audios": [],
    "effects": [],
    "filters": [],
    "handwrites": [],
    "stickers": [],
    "texts": [],
    "videos": []
  },
  "last_modified_platform": {
    "app_id": 3704,
    "app_source": "lv",
    "app_version": "4.2.0",
    "device_id": "9af4f431929e062ff217b53f97a4956c",
    "hard_disk_id": "547aa5351496e9d49dfb385244653b24",
    "mac_address": "d9aed9fab7102f4f36bd91f70f9b043e,10d2717e7d06a80d409fbb21516ebec0,c0f126ec1d37ccfde3369bf4bad2252f,0e7757ff99bacd8f6e70dd46dbdfbb04",
    "os": "windows",
    "os_version": "10.0.25381"
  },
  "materials": {
    "audio_balances": [],
    "audio_effects": [],
    "audio_fades": [],
    "audios": [],
    "beats": [],
    "canvases": [],
    "chromas": [],
    "color_curves": [],
    "drafts": [],
    "effects": [],
    "green_screens": [],
    "handwrites": [],
    "hsl": [],
    "images": [],
    "log_color_wheels": [],
    "manual_deformations": [],
    "masks": [],
    "material_animations": [],
    "placeholders": [],
    "plugin_effects": [],
    "primary_color_wheels": [],
    "realtime_denoises": [],
    "sound_channel_mappings": [],
    "speeds": [],
    "stickers": [],
    "tail_leaders": [],
    "text_templates": [],
    "texts": [],
    "transitions": [],
    "video_effects": [],
    "video_trackings": [],
    "videos": []
  },
  "mutable_config": null,
  "name": "",
  "new_version": "75.0.0",
  "platform": {
    "app_id": 3704,
    "app_source": "lv",
    "app_version": "4.2.0",
    "device_id": "9af4f431929e062ff217b53f97a4956c",
    "hard_disk_id": "547aa5351496e9d49dfb385244653b24",
    "mac_address": "d9aed9fab7102f4f36bd91f70f9b043e,10d2717e7d06a80d409fbb21516ebec0,c0f126ec1d37ccfde3369bf4bad2252f,0e7757ff99bacd8f6e70dd46dbdfbb04",
    "os": "windows",
    "os_version": "10.0.25381"
  },
  "relationships": [],
  "render_index_track_mode_on": false,
  "retouch_cover": null,
  "source": "default",
  "static_cover_image_path": "",
  "tracks": [],
  "update_time": 0,
  "version": 360000
}


================================================
FILE: template json/draft_meta_info.json
================================================
{
  "draft_cloud_capcut_purchase_info": "",
  "draft_cloud_last_action_download": false,
  "draft_cloud_purchase_info": "",
  "draft_cloud_template_id": "",
  "draft_cloud_tutorial_info": "",
  "draft_cloud_videocut_purchase_info": "",
  "draft_cover": "",
  "draft_deeplink_url": "",
  "draft_enterprise_info": {
    "draft_enterprise_extra": "",
    "draft_enterprise_id": "",
    "draft_enterprise_name": ""
  },
  "draft_fold_path": "",
  "draft_id": "",
  "draft_is_article_video_draft": false,
  "draft_is_from_deeplink": "false",
  "draft_materials": [
    { "type": 0, "value": [] },
    { "type": 1, "value": [] },
    { "type": 2, "value": [] },
    { "type": 3, "value": [] },
    { "type": 6, "value": [] },
    { "type": 7, "value": [] },
    { "type": 8, "value": [] }
  ],
  "draft_materials_copied_info": [],
  "draft_name": "",
  "draft_new_version": "",
  "draft_removable_storage_device": "",
  "draft_root_path": "",
  "draft_segment_extra_info": [],
  "draft_timeline_materials_size_": 0,
  "tm_draft_cloud_completed": "",
  "tm_draft_cloud_modified": 0,
  "tm_draft_create": 0,
  "tm_draft_modified": 0,
  "tm_duration": 0
}


================================================
FILE: test.py
================================================
from draft import Draft

print(Draft)
Download .txt
gitextract_e1k8nue9/

├── .gitignore
├── README.md
├── draft/
│   ├── Draft.py
│   ├── __init__.py
│   ├── material.py
│   ├── template.py
│   ├── track.py
│   └── util.py
├── main.py
├── project.py
├── template json/
│   ├── draft_content.json
│   └── draft_meta_info.json
└── test.py
Download .txt
SYMBOL INDEX (40 symbols across 5 files)

FILE: draft/__init__.py
  class Draft (line 8) | class Draft:
    method __init__ (line 15) | def __init__(self, name:str="Test"):
    method _medai_tpye (line 42) | def _medai_tpye(self,media):
    method add_media_to_materials (line 53) | def add_media_to_materials(self,file):
    method _content_material (line 73) | def _content_material(self,material:Material):
    method add_media_to_track (line 95) | def add_media_to_track(self,media,start=0,duration=0,index=0):
    method save (line 130) | def save(self):

FILE: draft/material.py
  class Material (line 5) | class Material:
    method __init__ (line 12) | def __init__(self, file) -> None:
    method data (line 43) | def data(self):
    method data (line 53) | def data(self, value):
    method to_material (line 56) | def to_material(self,file_path):
    method load_material (line 70) | def load_material(self,material):
    method video (line 82) | def video(self):
    method audio (line 93) | def audio(self):
    method text (line 102) | def text(self):
    method change_color (line 106) | def change_color(self,hex):

FILE: draft/template.py
  function canvase (line 4) | def canvase():
  function sound_channel_mapping (line 18) | def sound_channel_mapping():
  function speed (line 26) | def speed():
  function video (line 35) | def video():
  function material (line 102) | def material():
  function track (line 120) | def track():
  function segment (line 129) | def segment():
  function beat (line 169) | def beat():
  function audio (line 187) | def audio():
  function text (line 218) | def text():
  function material_animation (line 294) | def material_animation():

FILE: draft/track.py
  class Tracks (line 3) | class Tracks:
    method __init__ (line 5) | def __init__(self) -> None:
    method add_video_track (line 15) | def add_video_track(self,track_index=0):
    method add_audio_track (line 30) | def add_audio_track(self,track_index=0):
    method add_text_track (line 39) | def add_text_track(self,track_index=0):
    method _add_track (line 48) | def _add_track(self,tracks,track_type,track_index):
    method to_track (line 59) | def to_track(self,metetype,segment,track_index):
    method _composite (line 67) | def _composite(self):

FILE: draft/util.py
  function generate_id (line 6) | def generate_id():
  function write_json (line 12) | def write_json(path,data):
  function read_json (line 16) | def read_json(path):
  function new_folder (line 20) | def new_folder(folder_path):
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (29K chars).
[
  {
    "path": ".gitignore",
    "chars": 11,
    "preview": "__pycache__"
  },
  {
    "path": "README.md",
    "chars": 622,
    "preview": "# JianYingProDraft\n\n## 说明\n\n1. 实现原理 : `JianYingPro` 项目文件是 `json` 的形式存储的,只需要创建`draft_content.json`,`draft_mate_info.json` "
  },
  {
    "path": "draft/Draft.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "draft/__init__.py",
    "chars": 5272,
    "preview": "import os\nimport time\nimport util\nimport template\nfrom material import Material\nfrom track import Tracks\n\nclass Draft:\n\n"
  },
  {
    "path": "draft/material.py",
    "chars": 3657,
    "preview": "import template\nimport os\nfrom pymediainfo import MediaInfo\n\nclass Material:\n\n    media_type_mapping = {\n        \"video\""
  },
  {
    "path": "draft/template.py",
    "chars": 8523,
    "preview": "import time\nimport util\n\ndef canvase():\n    return {\n        \"album_image\": \"\",\n        \"blur\": 0.0,\n        \"color\": \"\""
  },
  {
    "path": "draft/track.py",
    "chars": 2273,
    "preview": "import template\n\nclass Tracks:\n\n    def __init__(self) -> None:\n        \"\"\"初始化轨道类型\n\n        Args:\n            tracks (li"
  },
  {
    "path": "draft/util.py",
    "chars": 690,
    "preview": "import os\nimport shutil\nimport uuid\nimport json\n\ndef generate_id():\n    \"\"\"\n        生成uuid\n    \"\"\"\n    return str(uuid.u"
  },
  {
    "path": "main.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "project.py",
    "chars": 773,
    "preview": "import random\nimport os\nimport selenium\nfrom draft import Draft\nfrom draft import Material\n\n# 新建项目\ndraft = Draft(\"测试草稿\")"
  },
  {
    "path": "template json/draft_content.json",
    "chars": 2907,
    "preview": "{\n  \"canvas_config\": { \"height\": 1080, \"ratio\": \"original\", \"width\": 1920 },\n  \"color_space\": -1,\n  \"config\": {\n    \"adj"
  },
  {
    "path": "template json/draft_meta_info.json",
    "chars": 1147,
    "preview": "{\n  \"draft_cloud_capcut_purchase_info\": \"\",\n  \"draft_cloud_last_action_download\": false,\n  \"draft_cloud_purchase_info\": "
  },
  {
    "path": "test.py",
    "chars": 37,
    "preview": "from draft import Draft\n\nprint(Draft)"
  }
]

About this extraction

This page contains the full source code of the xiaoyiv/JianYingProDraft GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (25.3 KB), approximately 7.2k tokens, and a symbol index with 40 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!