This commit is contained in:
2026-08-22 03:39:48 +00:00
parent 33d78759fe
commit 33ea2b7fcf
7 changed files with 324 additions and 13 deletions
+28 -7
View File
@@ -10,9 +10,12 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
threads = "8"
video_path = vod_path
video_chat = ""
chat_path = video_path.replace(".mp4", "_chat.json")
temp_with_chat = video_path.replace(".mp4", "_temp_with_chat.mp4")
temp_chat = video_path.replace(".mp4", "_temp_chat.mp4")
video_chat = video_path.replace(".mp4", "_with_chat.mp4")
video_chat_SS = video_path.replace(".mp4", "_SS_with_chat.mp4")
video_chat_over = video_path.replace(".mp4", "_over_with_chat.mp4")
mask_path = video_path.replace(".mp4", "_temp_chat_mask.mp4")
# Step 1: Pre-flight checks
@@ -23,7 +26,17 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
if not os.path.exists(chat_path):
print(f"❌ Error: Chat file not found: {chat_path}")
return False
if os.path.exists(temp_with_chat):
os.remove(temp_with_chat)
if layout == "side-by-side":
video_chat = video_chat_SS
elif layout == "overlay":
video_chat = video_chat_over
else:
return False
if os.path.exists(video_chat):
if not force:
print(f"❌ Error: Chat video already exists: {video_chat}")
@@ -33,6 +46,7 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
if os.path.exists(temp_chat):
os.remove(temp_chat)
if os.path.exists(mask_path):
os.remove(mask_path)
# Step 2: Render Chat to Video
@@ -74,16 +88,16 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
if layout == "side-by-side":
ffmpeg_cmd = (
f"ffmpeg -y -i {video_path} -i {temp_chat} "
f"-filter_complex '[1:v]scale=-1:H[scaled_chat];[0:v][scaled_chat]hstack=inputs=2[v]' "
f"-filter_complex '[1:v]scale=-1:ih[scaled_chat];[0:v][scaled_chat]hstack=inputs=2[v]' "
f"-map '[v]' -map 0:a? -c:v libx264 -crf 18 -preset slow -c:a copy "
f"-threads {threads} {video_chat}"
f"-threads {threads} {temp_with_chat}"
)
elif layout == "overlay":
ffmpeg_cmd = (
f"ffmpeg -y -i {video_path} -i {temp_chat} -i {mask_path} "
f"-filter_complex '[1:v][2:v]alphamerge[masked_chat];[0:v][masked_chat]overlay=x=0:y=10[v]' "
f"-map '[v]' -map 0:a? -c:v libx264 -crf 18 -preset slow -c:a copy "
f"-threads {threads} {video_chat}"
f"-threads {threads} {temp_with_chat}"
)
else:
raise ValueError("Invalid layout choice. Choose 'side-by-side' or 'overlay'.")
@@ -91,7 +105,8 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
ffmpeg_success = linux.run_command(ffmpeg_cmd, progress_prefix="FFmpeg Merge")
# Step 4: Final verification and cleanup
if ffmpeg_success and os.path.exists(video_chat):
if ffmpeg_success and os.path.exists(temp_with_chat):
os.rename(temp_with_chat, video_chat)
print("====================================================")
print(f"🎉 SUCCESS: Video processing complete!")
print(f"📁 Output Saved: {video_chat}")
@@ -101,11 +116,17 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
if os.path.exists(temp_chat):
print("🧹 Cleaning up temporary chat render video...")
os.remove(temp_chat)
if os.path.exists(mask_path):
os.remove(mask_path)
if os.path.exists(temp_with_chat):
os.remove(temp_with_chat)
return True
else:
print("❌ Error: FFmpeg failed to merge the video streams.")
os.remove(video_chat)
if os.path.exists(video_chat):
os.remove(video_chat)
if os.path.exists(temp_with_chat):
os.remove(temp_with_chat)
return False
if __name__ == "__main__":