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)
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
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.