shorts_factory/MakeVideo.py

164 lines
7.8 KiB
Python

import tkinter as tk
from tkinter import ttk, filedialog, simpledialog, Label
from gtts import gTTS
from moviepy.editor import *
from PIL import Image, ImageTk
import os
from datetime import datetime
from tkinter import messagebox
from moviepy.config import change_settings
change_settings({"IMAGEMAGICK_BINARY": r"C:\Program Files\ImageMagick-7.1.1-Q16-HDRI\magick.exe"})
class VideoCreatorApp:
def __init__(self, root):
self.root = root
self.setup_ui()
self.text_image_pairs = []
self.bgm_path = ''
self.save_path = "C:/Users/thdtl/Desktop/python/AutoYoutubeProject/Result" # 초기 저장 경로는 비워둡니다.
self.selected_item_index = None
def setup_ui(self):
self.root.title("YouTube Shorts Video Creator")
self.root.geometry("800x600") # Adjust the size of the window
self.listbox = tk.Listbox(self.root, width=70, height=20)
self.listbox.pack()
tk.Button(self.root, text="Add Text and Image", command=self.add_text_image_sequence).pack()
tk.Button(self.root, text="Edit Selected Text and Image", command=self.edit_selected_sequence).pack()
tk.Button(self.root, text="Delete Selected Text and Image", command=self.delete_selected_sequence).pack()
tk.Button(self.root, text="Set BGM", command=self.set_bgm).pack()
tk.Button(self.root, text="Remove BGM", command=self.remove_bgm).pack()
tk.Button(self.root, text="Set Save Path", command=self.set_save_path).pack()
tk.Button(self.root, text="Create Video", command=self.create_video).pack()
self.save_path_label = tk.Label(self.root, text="No path set")
self.save_path_label.pack()
self.image_label = Label(self.root)
self.image_label.pack()
self.progress = ttk.Progressbar(self.root, length=300, mode='determinate')
self.progress.pack()
self.listbox.bind('<<ListboxSelect>>', self.on_select)
def set_save_path(self):
# 사용자가 비디오를 저장할 경로를 선택할 수 있게 합니다.
path = filedialog.askdirectory() # 폴더 선택 다이얼로그를 엽니다.
if path:
self.save_path = path
self.save_path_label.config(text=path) # 선택된 경로를 레이블에 표시합니다.
def remove_bgm(self):
self.bgm_path = '' # 배경음악 경로를 빈 문자열로 설정
print("Background music removed") # 콘솔에 배경음악 제거 메시지 출력
def add_text_image_sequence(self):
text = simpledialog.askstring("Input", "Enter your text:", parent=self.root)
if text: # 텍스트가 입력되었다면
image_path = filedialog.askopenfilename(
title="Select related image",
filetypes=[("Image files", "*.jpg *.jpeg *.png *.gif")], # 이미지 파일 형식을 모두 허용
parent=self.root
)
# 이미지 선택을 취소하거나 비워둔 경우 None 또는 빈 문자열('')이 될 수 있습니다.
# 이 경우에도 텍스트는 저장되지만, 이미지 경로는 빈 문자열로 처리됩니다.
self.text_image_pairs.append((text, image_path if image_path else ""))
self.listbox.insert(tk.END, text)
else:
messagebox.showwarning("Warning", "No text was entered.")
def edit_selected_sequence(self):
if self.selected_item_index is not None:
new_text = simpledialog.askstring("Edit text", "Enter new text:", parent=self.root, initialvalue=self.text_image_pairs[self.selected_item_index][0])
if new_text:
new_image_path = filedialog.askopenfilename(title="Select new related image", filetypes=[("Image files", "*.jpg *.jpeg *.png")])
if new_image_path:
self.text_image_pairs[self.selected_item_index] = (new_text, new_image_path)
self.listbox.delete(self.selected_item_index)
self.listbox.insert(self.selected_item_index, new_text)
def delete_selected_sequence(self):
if self.selected_item_index is not None:
del self.text_image_pairs[self.selected_item_index]
self.listbox.delete(self.selected_item_index)
def on_select(self, event):
widget = event.widget
if widget.curselection():
index = int(widget.curselection()[0])
self.selected_item_index = index
# 선택된 항목에 대한 이미지 미리보기 표시
img_path = self.text_image_pairs[index][1]
self.display_image(img_path)
def set_bgm(self):
self.bgm_path = filedialog.askopenfilename(title="Select BGM file", filetypes=[("Audio files", "*.mp3 *.wav")])
def create_video(self):
self.progress['value'] = 0
total_steps = len(self.text_image_pairs)
current_step = 0
video_clips = [] # 최종 비디오 클립들을 저장할 리스트
for text, img_path in self.text_image_pairs:
# TTS 생성 및 오디오 클립 저장
tts = gTTS(text=text, lang='ko')
tts_file = f"temp_audio_{current_step}.mp3"
tts.save(tts_file)
tts_audio_clip = AudioFileClip(tts_file).volumex(2.0)
# 이미지 경로가 없는 경우, 투명한 배경의 클립 생성
if not img_path:
img_clip = ColorClip(size=(1080, 1920), color=(0, 0, 0, 0), duration=tts_audio_clip.duration)
else:
img_clip = ImageClip(img_path).set_duration(tts_audio_clip.duration).resize(newsize=(1080, 1920)).set_position('center')
# 자막 클립 생성
txt_clip = TextClip(text, font='Arial', fontsize=24, color='white', bg_color=None).set_pos('bottom').set_duration(tts_audio_clip.duration)
# 이미지 클립과 자막 클립을 합성
video_clip = CompositeVideoClip([img_clip, txt_clip], size=(1080, 1920)).set_duration(tts_audio_clip.duration).set_audio(tts_audio_clip)
video_clips.append(video_clip)
os.remove(tts_file)
current_step += 1
self.progress['value'] = (current_step / total_steps) * 100
self.root.update_idletasks()
# 모든 비디오 클립을 순차적으로 결합
final_video_clip = concatenate_videoclips(video_clips, method="compose")
# 배경음악 설정
if self.bgm_path:
bgm = AudioFileClip(self.bgm_path).volumex(0.5)
final_video_clip = final_video_clip.set_audio(CompositeAudioClip([final_video_clip.audio, bgm.set_duration(final_video_clip.duration)]))
# 최종 비디오 저장 경로 설정
if not self.save_path:
messagebox.showerror("Error", "Please set a save path first.")
return
if not os.path.exists("Result"):
os.makedirs("Result")
current_time = datetime.now().strftime("%Y%m%d%H%M%S")
final_video_file = os.path.join(self.save_path, f"{current_time}.mp4")
final_video_clip.write_videofile(final_video_file, fps=24, codec="libx264", audio_codec="aac")
self.progress['value'] = 100
messagebox.showinfo("Video Creator", f"Video creation completed successfully! Saved to {final_video_file}")
def display_image(self, img_path):
img = Image.open(img_path)
img = img.resize((200, 200), Image.Resampling.LANCZOS) # 이미지 크기 조정
img_tk = ImageTk.PhotoImage(img)
self.image_label.configure(image=img_tk)
self.image_label.image = img_tk # 참조 추가
if __name__ == "__main__":
root = tk.Tk()
app = VideoCreatorApp(root)
root.mainloop()