youtube-short-generator / youtube_short_generator.py
wower99's picture
updates
48ae64f
raw
history blame
7.85 kB
import os
import uuid
import shutil
from image_generator import ImageGenerator
from moviepy.editor import ImageClip, concatenate_videoclips,AudioFileClip
from function_wrap_center import add_text_to_image
from gtts import gTTS
from structured_output import StructuredOutputExtractor
from pydantic import BaseModel, Field
class YoutubeShortGenerator:
def __init__(self):
self.video_title = None
self.result = None
self.media_dir = 'generated_media'
self.generated_video_dir = None
self.image_dir = None
self.audio_clips_dir = None
self.video_path = None
os.makedirs(self.media_dir,exist_ok=True)
def title_to_keywords(self, title):
# Define your data extraction model here
class TopN(BaseModel):
title: str = Field(description="the title of the youtube video")
title_image_prompt: str = Field(description="highly detailed and descriptive image prompt for the background image of Title")
items: list[str] = Field(description="top n number of requested items")
items_image_prompts: list[str] = Field(description="highly detailed and descriptive image prompts for each item ")
# Assuming StructuredOutputExtractor is defined and functional
extractor = StructuredOutputExtractor(response_schema=TopN)
result = extractor.extract(title)
self.result = result
# create main directory for saving video related content i.e images, audio_clips
video_title = self.result.title
unique_id = uuid.uuid4().hex
folder_path = f"{self.media_dir}/generated_{video_title}_{unique_id}"
self.generated_video_dir = folder_path
return self
def generate_images(self):
if not self.result:
print("No data available. Call title_to_keywords first.")
return self
print(self.result,'inside generate_images()')
generator = ImageGenerator() # Your custom image generator
folder_path = f"{self.generated_video_dir}/generated_images" # Append unique ID
os.makedirs(folder_path, exist_ok=True) # Ensure directory is created
self.image_dir = folder_path
# Generate Title Image
# generator.generate_image(self.result.title_image_prompt, path=f"{folder_path}/title.png")
print("Title Prompt: ",self.result.title_image_prompt)
# generate images using stable-diffusion-turbo
generator.generate_image(self.result.title_image_prompt, path=f"{folder_path}/title.png")
print("Generating Images...")
image_prompts = self.result.items_image_prompts
print("items image prompts: ", image_prompts)
image_prompts = reversed(image_prompts)
print("Image Prompts: ", image_prompts) # Placeholder for actual image processing
# Generate and save images
for index, image_prompt in enumerate(image_prompts):
# generate images using stable-diffusion-turbo
generator.generate_image(image_prompt, f"{folder_path}/{index}.png" )
print(f"Image {index} saved.")
return self # Return self for further chaining if needed
def overlay_text_to_images(self):
if not self.result:
print("No data available. Call title_to_keywords first.")
return self
title_text = self.result.title
text_items = reversed(self.result.items)
print("text_items ",text_items)
# add text to title image
add_text_to_image(text=title_text,image_path=f"{self.image_dir}/title.png", save_to=f"{self.image_dir}/title.png")
# add text to other images
for index, text in enumerate(text_items):
image_path = f"{self.image_dir}/{index}.png"
add_text_to_image(text=text,image_path=image_path,is_title=False, save_to=image_path)
return self
def generate_audio_clips(self):
if not self.result:
print("No data available. Call title_to_keywords first.")
return self
print("Generating Title Audio...")
overlay_title = self.result.title
print("Title: ", overlay_title)
print("Generating Audio Clips...")
overlay_text_items = reversed(self.result.items)
print("Overlay Text: ", overlay_text_items) # Placeholder for actual text processing
folder_path = f"{self.generated_video_dir}/generated_audio_clips" # Append unique ID
self.audio_clips_dir = folder_path
os.makedirs(folder_path, exist_ok=True) # Ensure directory is created
# Generate title Audio
title_tts = gTTS(text=overlay_title)
title_tts.save(f"{folder_path}/title.mp3")
print(f"Title Audio clip title.mp3 saved.")
# Generate and save audio clips
for index, text_overlay in enumerate(overlay_text_items):
tts = gTTS(text=text_overlay) # Generate audio clip
tts.save(f"{folder_path}/{index}.mp3") # Save the audio as MP3
print(f"Audio clip {index} saved.")
return self # Return self for further chaining if needed
def make_video(self):
# Ensure title is included and sorted properly
audio_files = sorted(os.listdir(self.audio_clips_dir), key=lambda x: (x != "title.mp3", int(x.split(".")[0]) if x != "title.mp3" else -1))
image_files = sorted(os.listdir(self.image_dir), key=lambda x: (x != "title.png", int(x.split(".")[0]) if x != "title.png" else -1))
print("Sorted audio files:", audio_files)
print("Sorted image files:", image_files)
# Initialize audio clips
audio_clips = [AudioFileClip(os.path.join(self.audio_clips_dir, audio)) for audio in audio_files]
# Initialize image clips with matching durations
image_clips = [ImageClip(os.path.join(self.image_dir, image)).set_duration(audio.duration)
for image, audio in zip(image_files, audio_clips)]
# Attach audio to images
image_clips_with_audio = [image.set_audio(audio) for image, audio in zip(image_clips, audio_clips)]
# Concatenate all video clips
video_clip = concatenate_videoclips(image_clips_with_audio, method="compose")
# Save the final video
video_clip.write_videofile(
os.path.join(self.generated_video_dir, 'final_video.mp4'),
codec='libx264',
fps=24
)
self.remove_directory(self.image_dir)
self.remove_directory(self.audio_clips_dir)
existing_videos = sorted(
[os.path.join(self.media_dir, d) for d in os.listdir(self.media_dir)
if os.path.isdir(os.path.join(self.media_dir, d))],
key=os.path.getctime # Sort by creation time (oldest first)
)
if len(existing_videos) > 5:
for old_video_dir in existing_videos[:-5]: # Keep last 5, delete the rest
if old_video_dir != self.generated_video_dir: # Ensure we don't delete the current video
self.remove_directory(old_video_dir)
@staticmethod
def remove_directory(dir_path):
"""
Remove the specified directory and all its contents.
"""
if os.path.isdir(dir_path):
shutil.rmtree(dir_path)
print(f"{dir_path} and its contents have been removed.")
else:
print(f"{dir_path} does not exist or is not a directory.")
if __name__ == '__main__':
yt_short_generator = YoutubeShortGenerator()
result = yt_short_generator.title_to_keywords("top 3 Marvel Superheroes").generate_images().overlay_text_to_images().generate_audio_clips().make_video()