import os import subprocess import unicodedata from moviepy.video.io.VideoFileClip import VideoFileClip from moviepy.video.VideoClip import ColorClip from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip from moviepy import TextClip font = "./Montserrat.ttf" def normalize_filename(filename): name = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore').decode('ASCII') return name.lower() def cut_video_new_clip(input_path: str, start: float, end: float, output_path: str): video_codec = "libx264" with VideoFileClip(input_path) as clip: segment = clip.subclipped(start, end) fps = clip.fps or 30 segment.write_videofile( output_path, codec=video_codec, audio=False, remove_temp=True, fps=fps, ffmpeg_params=[ "-preset", "ultrafast", "-tune", "zerolatency", "-pix_fmt", "yuv420p", "-profile:v", "high", "-level", "4.1" ] ) def process_segment(input_path: str, top_text: str = "", bottom_text: str = "", filename="", idx=1) -> str: os.makedirs("outputs", exist_ok=True) os.makedirs(f"outputs/{filename}", exist_ok=True) final_width, final_height = 1080, 1920 top_h, middle_h, bottom_h = 480, 960, 480 with VideoFileClip(input_path) as clip: dur = clip.duration bg = ColorClip(size=(final_width, final_height), color=(255, 255, 255), duration=dur) video_resized = clip.resized(width=final_width) y = top_h + (middle_h - video_resized.h) // 2 video_resized = video_resized.with_position((0, y)) video_codec = "libx264" txt_top = TextClip( text=top_text, font_size=70, color="black", font=font, method="label", size=(final_width, top_h) ).with_duration(dur).with_position((0, 0)) txt_bot = TextClip( text=bottom_text, font_size=70, color="black", font=font, method="label", size=(final_width, bottom_h), ).with_duration(dur).with_position((0, final_height - bottom_h)) final = CompositeVideoClip([bg, video_resized, txt_top, txt_bot], size=(final_width, final_height)) output_path = f"outputs/{filename}/clip_{idx}.mp4" final.write_videofile( output_path, codec=video_codec, audio=False, remove_temp=True, ffmpeg_params=[ "-preset", "ultrafast", "-tune", "zerolatency", "-pix_fmt", "yuv420p", "-profile:v", "high", "-level", "4.1" ] ) final.close() return output_path def timestamp_to_seconds(ts): if isinstance(ts, (int, float)): return ts parts = ts.split(":") parts = [float(p) for p in parts] if len(parts) == 3: h, m, s = parts return h * 3600 + m * 60 + s elif len(parts) == 2: m, s = parts return m * 60 + s elif len(parts) == 1: return parts[0] else: raise ValueError(f"Timestamp inválido: {ts}") def process_full_video(filename: str, title: str, times: list = None) -> list: os.makedirs("temp", exist_ok=True) times = times or [] video_path = f"videos/{title}" processed = [] video_codec = "libx264" print(f"Total de trechos: {len(times)}") print(f"Codec de render: {video_codec}") for idx, interval in enumerate(times, start=1): start = timestamp_to_seconds(interval.get("start", 0)) end_raw = interval.get("end", None) end = timestamp_to_seconds(end_raw) if end_raw is not None else None top_text = interval.get("topText", "") bottom_text = interval.get("bottomText", "") if end is None: with VideoFileClip(video_path) as clip: end = clip.duration print(f"Cortando trecho {idx}: {start}s a {end}s") temp_path = f"temp/{os.path.splitext(filename)[0]}_{idx}.mp4" cut_video_new_clip(video_path, start, end, temp_path) out = process_segment(temp_path, top_text, bottom_text, filename, idx) processed.append(out) return processed