194 lines
6.6 KiB
Python
194 lines
6.6 KiB
Python
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
营销短视频生成自动化
|
||
功能清单
|
||
1、打开并读取任务
|
||
2、按照初始化剪映草稿、分别添加视频轨、音频轨、字幕轨和图片轨等、生成视频执行任务
|
||
"""
|
||
import asyncio
|
||
from pathlib import Path
|
||
|
||
import edge_tts
|
||
|
||
|
||
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())
|