feat: 🔖 Thumbnail creation & V1 release

pull/2058/head
Mohamed Moataz 1 year ago
parent 98aaffd865
commit 4fce079dba

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -54,7 +54,7 @@ def main(POST_ID=None) -> None:
length, number_of_comments = save_text_to_mp3(reddit_object)
length = math.ceil(length)
# length, number_of_comments = 42, 5
# length, number_of_comments = 120, 18
get_screenshots_of_reddit_posts(reddit_object, number_of_comments)
bg_config = {
@ -70,8 +70,15 @@ def main(POST_ID=None) -> None:
print("Video title:", video_data['title'])
print("Video description:", video_data['description'])
print("Video tags:", video_data['tags'])
# TODO: Generate thumbnail from text here
thumbnail = None
thumbnail = generate_image(thumbnail_text, f"./assets/temp/{reddit_object['thread_id']}/thumbnail_image.png")
# thumbnail = "thumbnail.png"
thumbnail = add_text(
thumbnail_path=thumbnail,
text=video_data["thumbnail_text"],
save_path=f"./assets/temp/{reddit_object['thread_id']}/thumbnail.png"
)
print("Thumbnail generated successfully at:", thumbnail)
upload_video_to_youtube(video_path, video_data, thumbnail)
@ -127,6 +134,7 @@ if __name__ == "__main__":
config is False and sys.exit()
from video_data_generation.gemini import get_video_data
from video_data_generation.image_generation import generate_image, add_text
from utils.youtube_uploader import upload_video_to_youtube
if (

@ -34,8 +34,8 @@ zoom = { optional = true, default = 1, example = 1.1, explanation = "Sets the br
run_every = { optional = false, default = 24, example = 5, explanation = "How often should the bot create a video (in hours).", type = "int", nmin = 4, nmax = 48, oob_error = "Please choose a number between 4 and 48." }
[settings.background]
background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["mudrunner", "granny-remake", ""], explanation = "Sets the background for the video based on game name" }
background_audio = { optional = true, default = "lofi", example = "chill-summer", options = ["eerie", "mysterious", "hybrid",""], explanation = "Sets the background audio for the video" }
background_video = { optional = true, default = "mudrunner", example = "rocket-league", options = ["mudrunner", "granny-remake", ""], explanation = "Sets the background for the video based on game name" }
background_audio = { optional = true, default = "eerie", example = "chill-summer", options = ["eerie", "mysterious", "hybrid",""], explanation = "Sets the background audio for the video" }
background_audio_volume = { optional = true, type = "float", nmin = 0, nmax = 1, default = 0.15, example = 0.05, explanation="Sets the volume of the background audio. If you don't want background audio, set it to 0.", oob_error = "The volume HAS to be between 0 and 1", input_error = "The volume HAS to be a float number between 0 and 1"}
enable_extra_audio = { optional = true, type = "bool", default = false, example = false, explanation="Used if you want to render another video without background audio in a separate folder", input_error = "The value HAS to be true or false"}
background_thumbnail = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Generate a thumbnail for the video (put a thumbnail.png file in the assets/backgrounds directory.)" }

@ -20,6 +20,8 @@ def draw_multiple_line_text(
image_width, image_height = image.size
lines = textwrap.wrap(text, width=wrap)
y = (image_height / 2) - (((Fontperm[1] + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
c = 0
for line in lines:
line_width, line_height = font.getsize(line)
if transparent:
@ -49,7 +51,11 @@ def draw_multiple_line_text(
font=font,
fill=shadowcolor,
)
if isinstance(text_color, tuple) and len(text_color) == 3:
draw.text(((image_width - line_width) / 2, y), line, font=font, fill=text_color)
elif isinstance(text_color, list):
draw.text(((image_width - line_width) / 2, y), line, font=font, fill=text_color[c % len(text_color)])
c += 1
y += line_height + padding

@ -1,9 +1,13 @@
from simple_youtube_api.Channel import Channel
from simple_youtube_api.LocalVideo import LocalVideo
import os
from video_data_generation import gemini
if os.path.exists("./utils/credentials.storage"):
os.remove("./utils/credentials.storage")
# logging into the channel
channel = Channel()
channel.login("./utils/client_secret.json", "./utils/credentials.storage")

@ -7,10 +7,12 @@ genai.configure(api_key=settings.config["settings"]["gemini"]["gemini_api_key"])
prompt1 = """I make some youtube videos where I get subreddits about ghost stories and make a video of it.
I will send a post to you and you should generate a YouTube video title, tags and description for it.
Also generate a short, relevant and catchy text to be written on the video thumbnail.
Only respond with the following:
title::: "The video title"
description::: "The video description"
tags::: "The video tags" without hashtags and separated by commas
thumbnail_text::: "The text to be wriiten on the video thumbnail"
Here is the post:
"""
@ -19,7 +21,7 @@ prompt2 = """Describe a thumbnail for a youtube video about ghosts and ghost sto
Only respond with the thumbnail description.
The description should be clear for an AI image generator model to generate it.
The video tags are:
The video description:
"""
model = genai.GenerativeModel('gemini-pro')
@ -27,19 +29,21 @@ model = genai.GenerativeModel('gemini-pro')
def get_data(post):
response = model.generate_content(prompt1 + post)
# print("Data:", response.prompt_feedback)
text = response.text.split('\n')
data = {i.split(':::')[0].strip(): i.split(':::')[1].strip() for i in text}
return data
def get_thumbnail(post):
thumbnail_response = model.generate_content(prompt2 + post)
# print('Thumbnail:', thumbnail_response.prompt_feedback)
return thumbnail_response.text
def get_video_data(post):
data = None
thumbnail = None
print("Generating video title & description...")
for i in range(2):
for i in range(3):
if i != 0: print("Try:", i+1)
try:
if data is None: data = get_data(post)
@ -47,7 +51,7 @@ def get_video_data(post):
thumbnail = get_thumbnail(data['tags'])
break
except Exception as e:
# print(e)
print(e)
continue
return data, thumbnail

@ -1,12 +1,15 @@
import os
import requests
from bs4 import BeautifulSoup
from PIL import Image, ImageDraw, ImageFont
from utils.imagenarator import draw_multiple_line_text
s = requests.session()
def renew_connection():
def get_csrf_token():
csrf_url = "https://image.plus/"
payload = {}
csrf_headers = {
'Host': 'image.plus',
@ -26,18 +29,15 @@ def renew_connection():
'Connection': 'close'
}
s.cookies.clear()
response = s.request("GET", csrf_url, headers=csrf_headers)
print(response.status_code)
soup = BeautifulSoup(response.text, 'html.parser')
return soup.find("meta", {"name":"csrf-token"})['content']
def generate_image(csrf_token, prompt=None):
def generate_image(prompt, save_path):
url = "https://image.plus/images/generate"
csrf_token = get_csrf_token()
prompt = "A ghost flying with a person sitting scared on a couch."
payload = f"prompt={prompt.replace(' ', '+')}&negative_prompt=&model=1&style=cinematic&samples=1&size=1152x896"
payload = f"prompt={prompt.replace(' ', '+')}&negative_prompt=&model=1&style=comic-book&samples=1&size=1152x896"
headers = {
'Host': 'image.plus',
'Content-Length': '106',
@ -60,7 +60,43 @@ def generate_image(csrf_token, prompt=None):
}
response = s.request("POST", url, headers=headers, data=payload)
return response.json()
image_url = response.json()['images'][0]['src']
image = s.get(image_url).content
with open(save_path, 'wb') as file:
file.write(image)
return save_path
def add_text(thumbnail_path, text, save_path):
bg = "./assets/backgrounds/background.jpg"
if thumbnail_path is None:
thumbnail_path = "./assets/thumbnail_bg.png"
img1 = Image.open(bg).convert("RGBA")
img2 = Image.open(thumbnail_path).resize((720, 720)).convert("RGBA")
img1.paste(img2, (0,0), mask=img2)
# font = ImageFont.truetype(os.path.join("fonts", "Another-Danger.otf"), 50)
# font = ImageFont.truetype(os.path.join("fonts", "Foul-Fiend.ttf"), 30)
font = ImageFont.truetype(os.path.join("fonts", "Mystery-Lake.ttf"), 75)
size = (560, 720)
image = Image.new("RGBA", size, (0, 0, 0, 0))
draw_multiple_line_text(
image,
text,
font,
[(255, 255, 255), (165, 42, 42)],
20,
wrap=20,
transparent=True
)
img1.paste(image, (720,0), mask=image)
img1.show()
img1.save(save_path)
return save_path
image = generate_image(renew_connection())
print(image)
if __name__ == '__main__':
prompt = "A hyper-realistic, scary image of a ghost flying in a room and a person sitting on a couch very scared looking at the ghost."
image_path = generate_image(prompt)
print(image_path)
Loading…
Cancel
Save