Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,7 @@ config.backup.yaml
# runtime
runtime/
dev/
installer_files/
installer_files/

core/capcut_api/
.vscode/
52 changes: 51 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ max_workers: 4
target_language: '简体中文'

# Whether to use Demucs for vocal separation before transcription
demucs: true
demucs: false

whisper:
# ["large-v3", "large-v3-turbo"]. Note: for zh model will force to use Belle/large-v3
Expand Down Expand Up @@ -179,3 +179,53 @@ language_split_with_space:
language_split_without_space:
- 'zh'
- 'ja'

# CapCut/剪映 settings
capcut:
installed: false
trans_draft_id: ''
dub_draft_id: ''
# 草稿目录路径
draft_folder: ''
# 启用导出剪映功能
enable_export: false
editor: "CapCut"


# 字幕位置设置
# 原始文本设置
orig_text:
font: '' # 字体
font_size: 8 # 字号
color: '#FFFFFF' # 颜色
bold: false # 粗体
italic: false # 斜体
underline: false # 下划线
stroke: true # 是否启用描边
stroke_color: '#000000' # 描边颜色
y_offset: -0.8 # Y方向位置移动,范围[-2,2],相对于原始视频的高度
stroke_width: 40 # 描边粗细
# 翻译文本设置
trans_text:
font: '' # 字体
font_size: 8 # 字号
color: '#FFFFFF' # 颜色
bold: false # 粗体
italic: false # 斜体
underline: false # 下划线
stroke: true # 是否启用描边
stroke_color: '#000000' # 描边颜色
stroke_width: 40 # 描边粗细
y_offset: -0.6 # Y方向位置移动,范围[-2,2],相对于原始视频的高度
# 配音文本设置
dub_text:
font: '' # 字体
font_size: 8 # 字号
color: '#FFFFFF' # 颜色
bold: false # 粗体
italic: false # 斜体
underline: false # 下划线
stroke: true # 是否启用描边
stroke_color: '#000000' # 描边颜色
stroke_width: 40 # 描边粗细
y_offset: -0.4 # Y方向位置移动,范围[-2,2],相对于原始视频的高度
109 changes: 105 additions & 4 deletions core/_12_dub_to_vid.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import platform
import subprocess
import os
import shutil

import cv2
import numpy as np
import requests
from rich.console import Console

from core._1_ytdlp import find_video_files
from core.asr_backend.audio_preprocess import normalize_audio_volume
from core.utils import *
from core.utils.models import *
from core.capcut_process.request_capcut_api import create_draft, add_video_impl, add_audio_track, add_subtitle, save_draft

from core._11_merge_audio import load_and_flatten_data, get_audio_files

console = Console()

Expand All @@ -28,10 +34,109 @@
TRANS_OUTLINE_WIDTH = 1
TRANS_BACK_COLOR = '&H33000000'

def create_capcut_draft(video_file, TARGET_WIDTH, TARGET_HEIGHT):
# 创建一个空白草稿
draft_folder = "/Users/sunguannan/Movies/JianyingPro/User Data/Projects/com.lveditor.draft"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

draft_data = create_draft(TARGET_WIDTH, TARGET_HEIGHT)
print(draft_data)

# 获取草稿id
draft_id = draft_data["output"]["draft_id"]

# 保存draft_id到配置文件,以便其他文件使用
update_key("capcut.dub_draft_id", draft_id)

# 添加原始视频
add_video_response = add_video_impl(
video_url=os.path.abspath(video_file),
draft_id=draft_id
)
print(add_video_response)

# 获取音频文件列表和时间信息
df, lines, new_sub_times = load_and_flatten_data(_8_1_AUDIO_TASK)
audios = get_audio_files(df)

# 添加每个音频片段到草稿中
for i, (audio_file, time_range) in enumerate(zip(audios, new_sub_times)):
if not os.path.exists(audio_file):
print(f"警告:音频文件 {audio_file} 不存在,跳过...")
continue

start_time, end_time = time_range
duration = end_time - start_time

# 添加音频到草稿
add_audio_response = add_audio_track(
audio_url=os.path.abspath(audio_file),
start=0, # 音频文件的起始时间
end=duration, # 音频文件的结束时间
target_start=start_time, # 设置音频在时间线上的起始位置
volume=1.0, # 设置音量
track_name="dub_tracks", # 为每个音频片段创建单独的轨道
draft_id=draft_id
)
print(f"添加音频 {audio_file} 结果:", add_audio_response)

# 添加dub字幕
# 从配置文件中获取配音文本设置
dub_font = load_key("capcut.dub_text.font")
dub_font_size = load_key("capcut.dub_text.font_size")
dub_color = load_key("capcut.dub_text.color")
dub_stroke = load_key("capcut.dub_text.stroke")
dub_stroke_color = load_key("capcut.dub_text.stroke_color")
dub_stroke_width = load_key("capcut.dub_text.stroke_width")
dub_y_offset = load_key("capcut.dub_text.y_offset")

add_srt_response = add_subtitle(
srt=os.path.abspath(DUB_SUB_FILE),
track_name="src_srt",
draft_id=draft_id,
font=dub_font,
font_size=dub_font_size,
font_color=dub_color,
border_color=dub_stroke_color if dub_stroke else None,
border_width=dub_stroke_width if dub_stroke else 0,
transform_y=dub_y_offset
)
print(add_srt_response)

# 保存草稿
save_response = save_draft(draft_id, draft_folder)
print("保存草稿结果:", save_response)

# 复制草稿文件夹到指定目录
source_draft_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "core/capcut_api", draft_id)
target_draft_dir = os.path.join(draft_folder, draft_id)

if os.path.exists(source_draft_dir):
# 如果目标目录已存在,先删除
if os.path.exists(target_draft_dir):
print(f"目标文件夹 {target_draft_dir} 已存在,正在删除...")
shutil.rmtree(target_draft_dir)

# 复制文件夹
print(f"正在将草稿文件夹从 {source_draft_dir} 复制到 {target_draft_dir}...")
shutil.move(source_draft_dir, target_draft_dir)
print(f"草稿文件夹复制完成")
else:
print(f"警告:源草稿文件夹 {source_draft_dir} 不存在")

return draft_id

def merge_video_audio():
"""Merge video and audio, and reduce video volume"""
VIDEO_FILE = find_video_files()
background_file = _BACKGROUND_AUDIO_FILE

video = cv2.VideoCapture(VIDEO_FILE)
TARGET_WIDTH = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
TARGET_HEIGHT = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
video.release()

# 创建剪映草稿
if load_key("capcut.enable_export"):
create_capcut_draft(VIDEO_FILE, TARGET_WIDTH, TARGET_HEIGHT)

if not load_key("burn_subtitles"):
rprint("[bold yellow]Warning: A 0-second black video will be generated as a placeholder as subtitles are not burned in.[/bold yellow]")
Expand All @@ -51,10 +156,6 @@ def merge_video_audio():
normalize_audio_volume(DUB_AUDIO, normalized_dub_audio)

# Merge video and audio with translated subtitles
video = cv2.VideoCapture(VIDEO_FILE)
TARGET_WIDTH = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
TARGET_HEIGHT = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
video.release()
rprint(f"[bold green]Video resolution: {TARGET_WIDTH}x{TARGET_HEIGHT}[/bold green]")

subtitle_filter = (
Expand Down
94 changes: 90 additions & 4 deletions core/_7_sub_into_vid.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import numpy as np
import platform
from core.utils import *
import requests
import shutil
from core.capcut_process.request_capcut_api import create_draft, add_video_impl, add_subtitle, save_draft


SRC_FONT_SIZE = 15
TRANS_FONT_SIZE = 17
Expand Down Expand Up @@ -40,10 +44,96 @@ def check_gpu_available():
except:
return False

def create_capcut_draft(video_file, TARGET_WIDTH, TARGET_HEIGHT):
# 从配置文件读取草稿目录路径
draft_folder = load_key("capcut.draft_folder")
response = create_draft(TARGET_WIDTH, TARGET_HEIGHT)
print(f"create_draft:{response}")

# 获取草稿id
draft_data = response
draft_id = draft_data["output"]["draft_id"]

# 保存draft_id到配置文件,以便其他文件使用
update_key("capcut.trans_draft_id", draft_id)

# 添加原始视频
add_video_response = add_video_impl(
video_url=os.path.abspath(video_file),
draft_id=draft_id
)
print(f"add_video_response:{add_video_response}")

# 从配置文件读取原始文本设置
orig_text_config = load_key("capcut.orig_text")

# 添加原始字幕
add_srt_response = add_subtitle(
srt=os.path.abspath(SRC_SRT),
track_name="src_srt",
draft_id=draft_id,
font = orig_text_config["font"],
font_size=orig_text_config["font_size"],
font_color=orig_text_config["color"],
border_color=orig_text_config["stroke_color"] if orig_text_config["stroke"] else None,
border_width=orig_text_config["stroke_width"] if orig_text_config["stroke"] else 0,
transform_y=orig_text_config["y_offset"]
)
print(add_srt_response)

# 从配置文件读取翻译文本设置
trans_text_config = load_key("capcut.trans_text")

# 添加翻译字幕
add_srt_response = add_subtitle(
srt=os.path.abspath(TRANS_SRT),
track_name="trans_srt",
draft_id=draft_id,
font = trans_text_config["font"],
font_size=trans_text_config["font_size"],
font_color=trans_text_config["color"],
border_color=trans_text_config["stroke_color"] if trans_text_config["stroke"] else None,
border_width=trans_text_config["stroke_width"] if trans_text_config["stroke"] else 0,
transform_y=trans_text_config["y_offset"]
)
print(add_srt_response)

# 保存草稿
save_response = save_draft(draft_id, draft_folder)
print("保存草稿结果:", save_response)

# 复制草稿文件夹到指定目录
source_draft_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "core/capcut_api", draft_id)
target_draft_dir = os.path.join(draft_folder, draft_id)

if os.path.exists(source_draft_dir):
# 如果目标目录已存在,先删除
if os.path.exists(target_draft_dir):
print(f"目标文件夹 {target_draft_dir} 已存在,正在删除...")
shutil.rmtree(target_draft_dir)

# 复制文件夹
print(f"正在将草稿文件夹从 {source_draft_dir} 复制到 {target_draft_dir}...")
shutil.move(source_draft_dir, target_draft_dir)
print(f"草稿文件夹复制完成")
else:
print(f"警告:源草稿文件夹 {source_draft_dir} 不存在")

return draft_id

def merge_subtitles_to_video():
video_file = find_video_files()
os.makedirs(os.path.dirname(OUTPUT_VIDEO), exist_ok=True)

video = cv2.VideoCapture(video_file)
TARGET_WIDTH = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
TARGET_HEIGHT = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
video.release()

# 创建剪映草稿
if load_key("capcut.enable_export"):
create_capcut_draft(video_file, TARGET_WIDTH, TARGET_HEIGHT)

# Check resolution
if not load_key("burn_subtitles"):
rprint("[bold yellow]Warning: A 0-second black video will be generated as a placeholder as subtitles are not burned in.[/bold yellow]")
Expand All @@ -62,10 +152,6 @@ def merge_subtitles_to_video():
rprint("Subtitle files not found in the 'output' directory.")
exit(1)

video = cv2.VideoCapture(video_file)
TARGET_WIDTH = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
TARGET_HEIGHT = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
video.release()
rprint(f"[bold green]Video resolution: {TARGET_WIDTH}x{TARGET_HEIGHT}[/bold green]")
ffmpeg_cmd = [
'ffmpeg', '-i', video_file,
Expand Down
1 change: 1 addition & 0 deletions core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .utils import *
from .utils.onekeycleanup import cleanup
from .utils.delete_retry_dubbing import delete_dubbing_files
from . import capcut_api
except ImportError:
pass

Expand Down
Loading