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('<>', 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()