Python/营销短视频生成自动化/main.py

243 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
营销短视频生成自动化
功能清单
1、打开并读取任务
2、按照初始化剪映草稿、分别添加视频轨、音频轨、字幕轨和图片轨等、生成视频执行任务
"""
import asyncio
from pathlib import Path
import edge_tts
task = {
"video_path": "", # 视频路径
"video_cover_path": "", # 视频首帧图片路径,可空
"pictures": [
{
"position": (0.0, 0.0), # 图片左上角X和Y位置于视频宽度百分比
"size_ratio": "", # 图片尺寸比例,于视频百分比
"picture_path": "", # 图片尺寸比例,于视频百分比
}, # 图片
],
"texts": [
{
"content": "", # 文字内容
"start": "", # 文字显示开始时间
"duration": "", # 文字展示时长,若为空值则默认为视频播放时长
"background_position": (0.0, 0.0), # 背景左上角X和Y位置
"background_color": "", # 背景颜色
"background_opacity": "", # 背景透明度
"stroke_color": "", # 边框颜色
"stroke_width": "", # 边框线宽
"font_size": "", # 字体大小
"font_color": "", # 字体颜色
},
],
}
from pycapcut import DraftFolder
import sys
# 指定剪映草稿文件夹地址
folder_path = {
"win32": r"C:\Users\admin\AppData\Local\JianyingPro\User Data\Projects\com.lveditor.draft".replace(
"\\", "/"
), # 若当前系统为windows则将剪映草稿文件夹原始字符串避免转义问题中反斜杠"\"转为正斜杠“/”
"darwin": None,
}.get(sys.platform)
if not folder_path:
raise RuntimeError("未指定剪映草稿文件夹地址")
# 初始化剪映草稿文件夹
folder = DraftFolder(folder_path)
print(folder)
exit()
async def audio_gen(
text: str, output_path: Path, voice_name: str = "zh-CN-XiaoxiaoNeural"
):
# 可用的中文语音列表
# chinese_voices = {
# "女声-晓晓": "zh-CN-XiaoxiaoNeural", # 年轻女声,自然
# "女声-晓辰": "zh-CN-XiaochenNeural", # 年轻女声,温暖
# "女声-晓墨": "zh-CN-XiaomoNeural", # 女声,富有表现力
# "男声-晓悠": "zh-CN-XiaoyouNeural", # 儿童音,可爱
# "男声-晓涵": "zh-CN-XiaohanNeural", # 年轻男声,温暖
# "男声-晓睿": "zh-CN-XiaoruiNeural", # 成熟男声,沉稳
# "女声-晓倩": "zh-CN-XiaoqianNeural", # 女声,成熟
# "男声-晓东": "zh-CN-XiaodongNeural", # 男声,权威
# }
# 生成语音
communicate = edge_tts.Communicate(
text, voice_name, rate="+0%", pitch="+0Hz", volume="+0%"
)
await communicate.save(output_path)
print(f"语音已保存到: {output_path}")
# ----
import pycapcut as capcut
from pycapcut import KeyframeProperty, SEC
from pycapcut import FontType, TextStyle, ClipSettings
from typing import List
import srt
async def video_merge_audio_and_caption(
video_path: Path,
audioPathList: List[Path],
image_path: Path,
subtitleList: List[srt.Subtitle],
output_path: Path,
):
PROJECT_DIR = "C:\\Users\\z4938\\AppData\\Local\\JianyingPro\\User Data\\Projects\\com.lveditor.draft"
draft_folder = capcut.DraftFolder(PROJECT_DIR)
script = draft_folder.create_draft("新草稿", 1920, 1080)
print("成功创建 draft剪映项目草稿")
# 添加视频轨
video_track_id = 1
script.add_track(
capcut.TrackType.video, track_name="视频", relative_index=video_track_id
)
video_mat = capcut.VideoMaterial(video_path)
video_seg = capcut.VideoSegment(video_mat, capcut.Timerange(0, video_mat.duration))
video_seg.add_keyframe(KeyframeProperty.alpha, video_seg.duration - SEC, 1.0)
video_seg.add_keyframe(KeyframeProperty.alpha, video_seg.duration, 0.0)
video_seg.volume = 0
script.add_segment(video_seg, "视频")
print(
f"视频素材导入成功素材ID{video_seg.material_id}, 片段id{video_seg.segment_id}"
)
# 添加logo图片轨
logo_track_id = 2
script.add_track(
capcut.TrackType.video, track_name="logo图片", relative_index=logo_track_id
)
logo_mat = capcut.VideoMaterial(image_path)
logo_seg = capcut.VideoSegment(logo_mat, capcut.Timerange(0, video_mat.duration))
logo_seg.add_keyframe(KeyframeProperty.alpha, video_seg.duration - SEC, 1.0)
logo_seg.add_keyframe(KeyframeProperty.alpha, video_seg.duration, 0.0)
script.add_segment(logo_seg, "logo图片")
print(f"logo导入成功视频轨道id{logo_track_id}")
# 添加音频轨
script.add_track(capcut.TrackType.audio, track_name="音频", relative_index=3)
for audio_path in audioPathList:
audio_mat = capcut.AudioMaterial(audio_path)
audio_seg = capcut.AudioSegment(
audio_mat,
capcut.Timerange(0, audio_mat.duration),
source_timerange=capcut.Timerange(0, audio_mat.duration),
)
script.add_segment(audio_seg, "音频")
print(
f"音频素材导入成功素材ID{audio_seg.material_id}, 片段id{audio_seg.segment_id}"
)
# 添加字幕轨
script.add_track(capcut.TrackType.text, track_name="字幕", relative_index=4)
for subtitle in subtitleList:
text_seg = capcut.TextSegment(
subtitle.content,
capcut.Timerange(
subtitle.start.total_seconds(), subtitle.end.total_seconds()
),
font=FontType.下午茶,
style=TextStyle(
size=5.0,
color=(0.7, 0.7, 1.0),
auto_wrapping=True,
underline=True,
align=1,
),
clip_settings=ClipSettings(transform_y=-0.8),
)
script.add_segment(text_seg, "字幕")
print("字幕添加成功")
export_result = script.export(
output_path=output_path, resolution="1080p", fps=30, quality="high"
)
print(f"视频导出完成result: {export_result}, 成品路径:{output_path}")
# ----
from datetime import timedelta
from moviepy import AudioFileClip
async def main():
TEXT_PATH_STR = "D:\\develop\\trkj\\resources\\tts_text.txt"
AUDIO_PATH_STR_FMT = "D:\\develop\\trkj\\resources\\audio_tts_{}.aac"
SRT_PATH_STR = "D:\\develop\\trkj\\resources\\tts_text_srt.srt"
VIDEO_PATH_STR = "D:\\develop\\trkj\\resources\\test_video.mp4"
IMAGE_PATH_STR = "D:\\develop\\trkj\\resources\\logo.png"
OUTPUT_PATH_STR = "D:\\develop\\trkj\\resources\\video_output.mp4"
videoPath = Path(VIDEO_PATH_STR)
audioPathList = list()
subtitleList = list()
imagePath = Path(IMAGE_PATH_STR)
outputPath = Path(OUTPUT_PATH_STR)
with open(TEXT_PATH_STR, "r", encoding="UTF-8") as text_f:
line = text_f.readline()
i = 0
next_start_seconds = timedelta(seconds=0.0)
while line:
audioPath = AUDIO_PATH_STR_FMT.format(i)
# 每行生成音频
await audio_gen(line, audioPath)
audioPathList.append(audioPath)
# 创建音频对应的字幕
audio = AudioFileClip(audioPath)
try:
current_start_seconds = next_start_seconds
current_end_seconds = next_start_seconds + timedelta(
seconds=audio.duration
)
subtitle = srt.Subtitle(
index=i + 1,
start=current_start_seconds,
end=current_end_seconds,
content=line.strip(),
)
subtitleList.append(subtitle)
finally:
audio.close()
line = text_f.readline()
i = i + 1
next_start_seconds = current_end_seconds
srt_content = srt.compose(subtitleList)
with open(SRT_PATH_STR, "w", encoding="UTF-8") as srt_file:
srt_file.write(srt_content)
print(f"字幕文件已生成: {SRT_PATH_STR}")
await video_merge_audio_and_caption(
videoPath, audioPathList, imagePath, subtitleList, outputPath
)
if __name__ == "__main__":
asyncio.run(main())