This commit is contained in:
2025-07-22 13:39:46 +08:00
parent dc94cc41c2
commit 0214a6069b
18 changed files with 69 additions and 1059 deletions

View File

@ -3,7 +3,7 @@ from utils.helpers import get_media_duration,get_media_info
from pathlib import Path
from typing import List, Dict, Optional
import streamlit as st # 為了存取 secrets
from scripts import step1_notion_sync, step2_translate_ipa
# from scripts_ import step1_notion_sync, step2_translate_ipa
import json
from notion_client import Client
from google.cloud import translate_v2 as translate
@ -567,7 +567,7 @@ class Project:
# 3. 初始化一個空的 AudioSegment 作為拼接的基礎
# 這是比「拿第一個檔案當基礎」更穩健的做法
combined_audio = AudioSegment.empty()
# 4. 遍歷所有音訊檔並依次拼接
for wav_file in wav_files:
# 讀取單個 .wav 檔案
@ -625,6 +625,7 @@ class Project:
try:
# 從 self.data 讀取各語言的文本行
title_line = self.data.get("title", "")
en_lines = [line.strip() for line in self.data.get("en", "").split('\n') if line.strip()]
zh_lines = [line.strip() for line in self.data.get("zh", "").split('\n') if line.strip()]
ipa_lines = [line.strip() for line in self.data.get("ipa", "").split('\n') if line.strip()]
@ -655,10 +656,11 @@ class Project:
subs.info["Title"] = self.name
# 6. 定義所有需要的樣式 (從您的腳本中精確複製)[1]
subs.styles["EN"] = pysubs2.SSAStyle(fontname="Noto Sans", fontsize=140, primarycolor=pysubs2.Color(255, 248, 231), outlinecolor=pysubs2.Color(255, 248, 231), outline=2, alignment=pysubs2.Alignment.TOP_CENTER, marginv=280)
subs.styles["IPA"] = pysubs2.SSAStyle(fontname="Noto Sans", fontsize=110, primarycolor=pysubs2.Color(255, 140, 0), outlinecolor=pysubs2.Color(255, 140, 0), outline=1, alignment=pysubs2.Alignment.TOP_CENTER, marginv=340)
subs.styles["ZH"] = pysubs2.SSAStyle(fontname="Noto Sans TC", fontsize=140, primarycolor=pysubs2.Color(102, 128, 153), outlinecolor=pysubs2.Color(102, 128, 153), outline=1, alignment=pysubs2.Alignment.TOP_CENTER, marginv=440)
subs.styles["NUMBER"] = pysubs2.SSAStyle(fontname="Segoe UI Symbol", fontsize=120, primarycolor=pysubs2.Color(144, 144, 144), outlinecolor=pysubs2.Color(144, 144, 144), bold=True, outline=1, borderstyle=1,alignment=pysubs2.Alignment.TOP_RIGHT, marginl=0, marginr=260, marginv=160)
subs.styles["TITLE"] = pysubs2.SSAStyle(fontname="源泉圓體丹 R", fontsize=80, primarycolor=pysubs2.Color(230, 221, 196), outlinecolor=pysubs2.Color(230, 221, 196), outline=0, borderstyle=2, alignment=pysubs2.Alignment.TOP_CENTER, marginl=0, marginr=0, marginv=200)
subs.styles["EN"] = pysubs2.SSAStyle(fontname="Noto Sans", fontsize=140, primarycolor=pysubs2.Color(255, 248, 231), outlinecolor=pysubs2.Color(255, 248, 231), outline=2,borderstyle=2, alignment=pysubs2.Alignment.TOP_CENTER, marginv=400)
subs.styles["IPA"] = pysubs2.SSAStyle(fontname="Noto Sans", fontsize=110, primarycolor=pysubs2.Color(255, 140, 0), outlinecolor=pysubs2.Color(255, 140, 0), outline=1, alignment=pysubs2.Alignment.TOP_CENTER, marginv=500)
subs.styles["ZH"] = pysubs2.SSAStyle(fontname="Noto Sans TC", fontsize=140, primarycolor=pysubs2.Color(152, 188, 193), outlinecolor=pysubs2.Color(152, 188, 193), outline=1, alignment=pysubs2.Alignment.TOP_CENTER, marginv=600)
subs.styles["NUMBER"] = pysubs2.SSAStyle(fontname="NaiKaiFont", fontsize=60, primarycolor=pysubs2.Color(164, 124, 104), outlinecolor=pysubs2.Color(164, 124, 104),outline=1, angle=-10, borderstyle=2,alignment=pysubs2.Alignment.TOP_RIGHT, marginl=0, marginr=260, marginv=160)
# 7. 遍歷音訊檔,生成四層字幕事件
st.session_state.operation_status = {
@ -673,10 +675,10 @@ class Project:
end_time = current_time_ms + duration_ms
# 為每一層字幕建立一個事件
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=en_lines[i], style="EN"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=f"[{ipa_lines[i]}]", style="IPA"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=zh_lines[i], style="ZH"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=i, style="NUMBER"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=f"{{\\fad(300, 300)}}{en_lines[i]}" , style="EN"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=f"{{\\fad(300, 300)}}/{ipa_lines[i]}/" , style="IPA"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=f"{{\\fad(300, 300)}}{zh_lines[i]}" , style="ZH"))
subs.append(pysubs2.SSAEvent(start=start_time, end=end_time, text=f"{{\\fad(300, 300)}}{str(i+1)}" , style="NUMBER"))
current_time_ms = end_time
st.session_state.operation_status = {
@ -684,6 +686,7 @@ class Project:
"value": (i + 1) / total_files,
"message": f"正在處理字幕... ({i+1}/{total_files})"
}
subs.insert(0, pysubs2.SSAEvent(start=0, end=end_time, text=title_line, style="TITLE"))
# 8. 儲存 .ass 檔案
subs.save(str(ass_path))
st.session_state.operation_status = {
@ -736,7 +739,7 @@ class Project:
final_video_path = self.paths['final_video']
bg_final_path = output_dir / "bg_final.mp4"
transition_duration = 1.0
print("111")
for file_path in [logo_video, open_video, end_video, audio_path, ass_path]:
if not file_path or not file_path.exists():
st.session_state.operation_status = {
@ -744,7 +747,6 @@ class Project:
"message": f"缺少必需的檔案: {e}"
}
return
print("222")
base_videos = sorted([p for p in temp_video_dir.iterdir() if p.is_file() and p.suffix.lower() in ['.mp4', '.mov']])
if not base_videos:
@ -753,7 +755,6 @@ class Project:
"message": f"資料夾中沒有影片可供合成。: {e}"
}
return
print("333")
p_loop_count, error_msg = self.calculate_loop_count(transition_duration=transition_duration)
@ -761,7 +762,6 @@ class Project:
# 如果計算出錯,拋出一個錯誤讓外層的 except 捕捉
raise ValueError(f"計算循環次數時失敗: {error_msg}")
print("444")
# --- 2. 一步式生成主要內容影片 (bg_final.mp4) ---
if not bg_final_path.exists():
print(f"⚙️ 準備一步式生成主要內容影片 (循環 {p_loop_count} 次)...")
@ -899,10 +899,8 @@ class Project:
video_paths = [p for p in video_folder.iterdir() if p.is_file() and p.suffix.lower() in ['.mp4', '.mov']]
video_lengths = [get_media_duration(p) for p in video_paths]
video_lengths = [l for l in video_lengths if l is not None and l > 0]
print("ccc")
if not video_lengths:
return None, "在 `test` 資料夾中找不到有效的影片檔案。"
print("ddd")
n = len(video_lengths)
m = sum(video_lengths)
tr = transition_duration