Update app.py
Browse files
app.py
CHANGED
|
@@ -99,6 +99,15 @@ import emoji
|
|
| 99 |
import requests
|
| 100 |
from PIL import Image, ImageDraw, ImageFont
|
| 101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
def create_text_image_2(
|
| 103 |
text: str,
|
| 104 |
width: int,
|
|
@@ -122,12 +131,27 @@ def create_text_image_2(
|
|
| 122 |
all_emojis = emoji.emoji_list(text)
|
| 123 |
plain_text = emoji.replace_emoji(text, replace='')
|
| 124 |
|
| 125 |
-
# Measure text size
|
| 126 |
-
|
|
|
|
|
|
|
| 127 |
total_emoji_width = len(all_emojis) * font_size
|
| 128 |
full_width = text_width + total_emoji_width + 5 * len(all_emojis)
|
| 129 |
|
| 130 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
if align == "left":
|
| 132 |
x_start = 20
|
| 133 |
elif align == "right":
|
|
@@ -140,7 +164,7 @@ def create_text_image_2(
|
|
| 140 |
# Draw the plain text
|
| 141 |
draw.text((x_start, y_start), plain_text, font=font, fill=text_color)
|
| 142 |
|
| 143 |
-
# Get emoji positions
|
| 144 |
x = x_start + text_width + 5
|
| 145 |
for em in all_emojis:
|
| 146 |
char = em["emoji"]
|
|
@@ -339,22 +363,21 @@ def edit_video(video_path):
|
|
| 339 |
)
|
| 340 |
return output_path
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
def edit_video_raw(video_path: str) -> str:
|
| 343 |
-
import os, uuid, random
|
| 344 |
-
import numpy as np
|
| 345 |
-
from moviepy.editor import (
|
| 346 |
-
VideoFileClip, ImageClip, ColorClip, TextClip,
|
| 347 |
-
CompositeVideoClip
|
| 348 |
-
)
|
| 349 |
-
|
| 350 |
# Load main video
|
| 351 |
clip = VideoFileClip(video_path)
|
| 352 |
vw, vh = 1080, 1920
|
| 353 |
|
| 354 |
CAPTION_H = 179
|
| 355 |
LAUGH_H = 396
|
| 356 |
-
MID_H = 164
|
| 357 |
-
MAIN_H =
|
| 358 |
|
| 359 |
if clip.duration < 6:
|
| 360 |
raise ValueError("Main video must be at least 6 seconds.")
|
|
@@ -389,27 +412,25 @@ def edit_video_raw(video_path: str) -> str:
|
|
| 389 |
.set_start(0)
|
| 390 |
.set_position((
|
| 391 |
0,
|
| 392 |
-
CAPTION_H
|
| 393 |
))
|
| 394 |
)
|
| 395 |
|
| 396 |
-
|
| 397 |
freeze_frame = (
|
| 398 |
laugh_start.to_ImageClip()
|
| 399 |
.set_start(2)
|
| 400 |
.set_duration(max(0, clip.duration - 4))
|
| 401 |
-
.set_position((0, CAPTION_H
|
| 402 |
)
|
| 403 |
laugh_end = (
|
| 404 |
resized_laugh.subclip(laugh_raw.duration - 2)
|
| 405 |
.set_start(clip.duration - 2)
|
| 406 |
.set_position((
|
| 407 |
0,
|
| 408 |
-
CAPTION_H
|
| 409 |
))
|
| 410 |
)
|
| 411 |
|
| 412 |
-
|
| 413 |
# Mid caption
|
| 414 |
mid_text = random.choice([
|
| 415 |
"Pura 1 din laga tab ye reel mili π€£",
|
|
@@ -419,7 +440,8 @@ def edit_video_raw(video_path: str) -> str:
|
|
| 419 |
])
|
| 420 |
mid_img = create_text_image_2(
|
| 421 |
mid_text, vw, MID_H,
|
| 422 |
-
font_size=
|
|
|
|
| 423 |
bg_color=(0, 0, 0), text_color=(255, 255, 255)
|
| 424 |
)
|
| 425 |
mid_caption_clip = ImageClip(np.array(mid_img)) \
|
|
@@ -429,29 +451,25 @@ def edit_video_raw(video_path: str) -> str:
|
|
| 429 |
|
| 430 |
# Main video
|
| 431 |
main_video_y = CAPTION_H + LAUGH_H + MID_H
|
| 432 |
-
resized_main = clip.resize(
|
|
|
|
| 433 |
main_video = resized_main.set_start(0).set_position((
|
| 434 |
-
|
| 435 |
-
main_video_y
|
| 436 |
))
|
| 437 |
|
| 438 |
-
|
| 439 |
-
|
| 440 |
# Light filter over main video to reduce copyright detection
|
| 441 |
overlay = ColorClip(size=(vw, MAIN_H), color=(255, 255, 255), duration=clip.duration) \
|
| 442 |
.set_opacity(0.1) \
|
| 443 |
.set_position((0, main_video_y))
|
| 444 |
|
| 445 |
-
# Watermark: center-right inside main video
|
| 446 |
-
# Replace watermark_img creation
|
| 447 |
-
|
| 448 |
# Final composition
|
| 449 |
final = CompositeVideoClip([
|
| 450 |
caption_clip,
|
| 451 |
laugh_start, freeze_frame, laugh_end,
|
| 452 |
mid_caption_clip,
|
| 453 |
main_video,
|
| 454 |
-
|
| 455 |
], size=(vw, vh))
|
| 456 |
|
| 457 |
# Export
|
|
@@ -471,7 +489,6 @@ def edit_video_raw(video_path: str) -> str:
|
|
| 471 |
clip.close(), laugh_raw.close(), final.close()
|
| 472 |
return out_path
|
| 473 |
|
| 474 |
-
|
| 475 |
# βββββββββββββββββββββββββββββ LOGGING
|
| 476 |
logging.basicConfig(
|
| 477 |
level=logging.INFO,
|
|
|
|
| 99 |
import requests
|
| 100 |
from PIL import Image, ImageDraw, ImageFont
|
| 101 |
|
| 102 |
+
import os, uuid, random
|
| 103 |
+
import numpy as np
|
| 104 |
+
import emoji
|
| 105 |
+
import requests
|
| 106 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 107 |
+
from moviepy.editor import (
|
| 108 |
+
VideoFileClip, ImageClip, ColorClip, CompositeVideoClip
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
def create_text_image_2(
|
| 112 |
text: str,
|
| 113 |
width: int,
|
|
|
|
| 131 |
all_emojis = emoji.emoji_list(text)
|
| 132 |
plain_text = emoji.replace_emoji(text, replace='')
|
| 133 |
|
| 134 |
+
# Measure text size and adjust font size
|
| 135 |
+
text_bbox = draw.textbbox((0, 0), plain_text, font=font)
|
| 136 |
+
text_width = text_bbox[2] - text_bbox[0]
|
| 137 |
+
text_height = text_bbox[3] - text_bbox[1]
|
| 138 |
total_emoji_width = len(all_emojis) * font_size
|
| 139 |
full_width = text_width + total_emoji_width + 5 * len(all_emojis)
|
| 140 |
|
| 141 |
+
# Adjust font size to fit within width and height
|
| 142 |
+
while (full_width > width - 40 or text_height > height - 10) and font_size > 10:
|
| 143 |
+
font_size -= 2
|
| 144 |
+
try:
|
| 145 |
+
font = ImageFont.truetype("DejaVuSans-Bold.ttf", size=font_size)
|
| 146 |
+
except OSError:
|
| 147 |
+
font = ImageFont.load_default()
|
| 148 |
+
text_bbox = draw.textbbox((0, 0), plain_text, font=font)
|
| 149 |
+
text_width = text_bbox[2] - text_bbox[0]
|
| 150 |
+
text_height = text_bbox[3] - text_bbox[1]
|
| 151 |
+
total_emoji_width = len(all_emojis) * font_size
|
| 152 |
+
full_width = text_width + total_emoji_width + 5 * len(all_emojis)
|
| 153 |
+
|
| 154 |
+
# X-offset based on alignment
|
| 155 |
if align == "left":
|
| 156 |
x_start = 20
|
| 157 |
elif align == "right":
|
|
|
|
| 164 |
# Draw the plain text
|
| 165 |
draw.text((x_start, y_start), plain_text, font=font, fill=text_color)
|
| 166 |
|
| 167 |
+
# Get emoji positions
|
| 168 |
x = x_start + text_width + 5
|
| 169 |
for em in all_emojis:
|
| 170 |
char = em["emoji"]
|
|
|
|
| 363 |
)
|
| 364 |
return output_path
|
| 365 |
|
| 366 |
+
import os, uuid, random
|
| 367 |
+
import numpy as np
|
| 368 |
+
from moviepy.editor import (
|
| 369 |
+
VideoFileClip, ImageClip, ColorClip, TextClip,
|
| 370 |
+
CompositeVideoClip
|
| 371 |
+
)
|
| 372 |
def edit_video_raw(video_path: str) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
# Load main video
|
| 374 |
clip = VideoFileClip(video_path)
|
| 375 |
vw, vh = 1080, 1920
|
| 376 |
|
| 377 |
CAPTION_H = 179
|
| 378 |
LAUGH_H = 396
|
| 379 |
+
MID_H = 120 # Reduced from 164 to 120
|
| 380 |
+
MAIN_H = vh - CAPTION_H - LAUGH_H - MID_H # Calculate remaining height for main video
|
| 381 |
|
| 382 |
if clip.duration < 6:
|
| 383 |
raise ValueError("Main video must be at least 6 seconds.")
|
|
|
|
| 412 |
.set_start(0)
|
| 413 |
.set_position((
|
| 414 |
0,
|
| 415 |
+
CAPTION_H # Position below caption to prevent overlap
|
| 416 |
))
|
| 417 |
)
|
| 418 |
|
|
|
|
| 419 |
freeze_frame = (
|
| 420 |
laugh_start.to_ImageClip()
|
| 421 |
.set_start(2)
|
| 422 |
.set_duration(max(0, clip.duration - 4))
|
| 423 |
+
.set_position((0, CAPTION_H)) # Position below caption
|
| 424 |
)
|
| 425 |
laugh_end = (
|
| 426 |
resized_laugh.subclip(laugh_raw.duration - 2)
|
| 427 |
.set_start(clip.duration - 2)
|
| 428 |
.set_position((
|
| 429 |
0,
|
| 430 |
+
CAPTION_H # Position below caption
|
| 431 |
))
|
| 432 |
)
|
| 433 |
|
|
|
|
| 434 |
# Mid caption
|
| 435 |
mid_text = random.choice([
|
| 436 |
"Pura 1 din laga tab ye reel mili π€£",
|
|
|
|
| 440 |
])
|
| 441 |
mid_img = create_text_image_2(
|
| 442 |
mid_text, vw, MID_H,
|
| 443 |
+
font_size=48, # Initial font size, will be adjusted dynamically
|
| 444 |
+
align="center",
|
| 445 |
bg_color=(0, 0, 0), text_color=(255, 255, 255)
|
| 446 |
)
|
| 447 |
mid_caption_clip = ImageClip(np.array(mid_img)) \
|
|
|
|
| 451 |
|
| 452 |
# Main video
|
| 453 |
main_video_y = CAPTION_H + LAUGH_H + MID_H
|
| 454 |
+
resized_main = clip.resize(height=MAIN_H) # Scale to fit MAIN_H, preserve aspect ratio
|
| 455 |
+
main_video_x = (vw - resized_main.w) // 2 if resized_main.w > vw else 0 # Center horizontally if wider than vw
|
| 456 |
main_video = resized_main.set_start(0).set_position((
|
| 457 |
+
main_video_x,
|
| 458 |
+
main_video_y # Position at the calculated y-coordinate
|
| 459 |
))
|
| 460 |
|
|
|
|
|
|
|
| 461 |
# Light filter over main video to reduce copyright detection
|
| 462 |
overlay = ColorClip(size=(vw, MAIN_H), color=(255, 255, 255), duration=clip.duration) \
|
| 463 |
.set_opacity(0.1) \
|
| 464 |
.set_position((0, main_video_y))
|
| 465 |
|
|
|
|
|
|
|
|
|
|
| 466 |
# Final composition
|
| 467 |
final = CompositeVideoClip([
|
| 468 |
caption_clip,
|
| 469 |
laugh_start, freeze_frame, laugh_end,
|
| 470 |
mid_caption_clip,
|
| 471 |
main_video,
|
| 472 |
+
overflow
|
| 473 |
], size=(vw, vh))
|
| 474 |
|
| 475 |
# Export
|
|
|
|
| 489 |
clip.close(), laugh_raw.close(), final.close()
|
| 490 |
return out_path
|
| 491 |
|
|
|
|
| 492 |
# βββββββββββββββββββββββββββββ LOGGING
|
| 493 |
logging.basicConfig(
|
| 494 |
level=logging.INFO,
|