Compare commits

...

17 Commits

Author SHA1 Message Date
d737177eab Ajusta 3000k bitrate 2025-08-05 21:23:29 +02:00
6420a02090 revert 2be19ee02c
revert remove bitrate
2025-08-05 21:19:31 +02:00
2be19ee02c remove bitrate 2025-08-05 20:32:07 +02:00
98613a0002 Implementa desacoplamento de I/O 2025-08-05 14:58:44 +02:00
501c45cad7 Ajusta callback 2025-08-05 14:43:12 +02:00
0fd0cda460 Ajusta rabbit 2025-08-05 04:39:03 +02:00
dd4f9fc51c Ajusta rabbitmq 2025-08-05 03:59:08 +02:00
6288d77d46 Ajusta FPS e bitrate de render 2025-08-05 00:02:00 +02:00
Leonardo Mortari
8f5934d576 Add param 2025-08-04 13:17:42 -03:00
Leonardo Mortari
a941eb6b98 Adjusta vars de font e videocodec 2025-08-04 13:08:57 -03:00
Leonardo Mortari
503f2817d2 Merge branch 'master' of https://gitea.leolitas.work.gd/admin/video-render-api 2025-08-04 09:04:55 -03:00
Leonardo Mortari
85b5717595 Adiciona vars faltantes 2025-08-04 09:04:51 -03:00
Leonardo Mortari
9c626a1e4a Altera background de branco para preto, altera cor da letra para branco, cria um auto-resize para formatar os textos com quebras de linhas 2025-08-04 09:03:34 -03:00
ad84469037 Remove parametro de audio false 2025-08-03 23:29:35 +02:00
561be6a182 Adjust queue 2025-08-02 21:45:52 +02:00
Leonardo Mortari
1e15544687 Muda nome do environment 2025-08-02 14:09:28 -03:00
Leonardo Mortari
927eabb2d5 Remove webhook e adiciona push na fila 2025-08-02 14:09:06 -03:00
2 changed files with 111 additions and 60 deletions

View File

@@ -6,9 +6,35 @@ from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
from moviepy import TextClip
font = "./Montserrat.ttf"
font_size = 70
video_codec = "libx264"
def auto_wrap_text(text, max_width):
if not text:
return ""
words = text.split()
lines = []
line = ""
for word in words:
test_line = f"{line} {word}".strip()
test_clip = TextClip(text=test_line, font=font, font_size=font_size, color='white', method='label')
if test_clip.w > max_width and line != "":
lines.append(line)
line = word
else:
line = test_line
test_clip.close()
lines.append(line)
return "\n".join(lines)
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)
@@ -17,9 +43,9 @@ def cut_video_new_clip(input_path: str, start: float, end: float, output_path: s
segment.write_videofile(
output_path,
codec=video_codec,
audio=False,
remove_temp=True,
fps=fps,
bitrate="3000k",
ffmpeg_params=[
"-preset", "ultrafast",
"-tune", "zerolatency",
@@ -38,25 +64,26 @@ def process_segment(input_path: str, top_text: str = "", bottom_text: str = "",
with VideoFileClip(input_path) as clip:
dur = clip.duration
bg = ColorClip(size=(final_width, final_height), color=(255, 255, 255), duration=dur)
bg = ColorClip(size=(final_width, final_height), color=(0, 0, 0), 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"
wrapped_top_text = auto_wrap_text(top_text, final_width - 40)
wrapped_bottom_text = auto_wrap_text(bottom_text, final_width - 40)
txt_top = TextClip(
text=top_text,
text=wrapped_top_text,
font_size=70,
color="black",
color="white",
font=font,
method="label",
size=(final_width, top_h)
).with_duration(dur).with_position((0, 0))
txt_bot = TextClip(
text=bottom_text,
text=wrapped_bottom_text,
font_size=70,
color="black",
color="white",
font=font,
method="label",
size=(final_width, bottom_h),
@@ -69,8 +96,9 @@ def process_segment(input_path: str, top_text: str = "", bottom_text: str = "",
final.write_videofile(
output_path,
codec=video_codec,
audio=False,
remove_temp=True,
fps=30,
bitrate="3000k",
ffmpeg_params=[
"-preset", "ultrafast",
"-tune", "zerolatency",
@@ -109,8 +137,6 @@ def process_full_video(filename: str, times: list = None) -> list:
video_path = f"videos/{filename}"
processed = []
video_codec = "libx264"
print(f"Total de trechos: {len(times)}")
print(f"Codec de render: {video_codec}")

123
main.py
View File

@@ -1,8 +1,7 @@
import os
import pika
import json
import requests
import time
from components.video import process_full_video
RABBITMQ_HOST = os.environ.get('RABBITMQ_HOST', 'rabbitmq')
@@ -10,69 +9,95 @@ RABBITMQ_PORT = int(os.environ.get('RABBITMQ_PORT', 5672))
RABBITMQ_USER = os.environ.get('RABBITMQ_USER', 'admin')
RABBITMQ_PASS = os.environ.get('RABBITMQ_PASS')
RABBITMQ_QUEUE = os.environ.get('RABBITMQ_QUEUE', 'to-render')
RABBITMQ_UPLOAD_QUEUE = os.environ.get('RABBITMQ_UPLOAD_QUEUE', 'to-upload')
if not RABBITMQ_PASS:
raise RuntimeError("RABBITMQ_PASS não definido no ambiente")
def callback(ch, method, properties, body):
try:
data = json.loads(body)
filename = data.get("filename")
times = data.get("times", [])
webhook_url = data.get("webhookUrl")
url = data.get("url")
video_id = data.get("videoId")
print(f"Processando vídeo: {filename}")
processed_files = process_full_video(filename, times)
payload = {
"videosProcessedQuantity": len(processed_files),
"filename": filename,
"processedFiles": processed_files,
"url": url,
"videoId": video_id,
"error": False,
}
except Exception as e:
payload = {
"videosProcessedQuantity": 0,
"filename": filename if 'filename' in locals() else None,
"processedFiles": [],
"url": url if 'url' in locals() else None,
"videoId": video_id if 'video_id' in locals() else None,
"error": str(e),
}
print(f"Erro no processamento: {e}")
try:
if webhook_url:
resp = requests.post(webhook_url, json=payload, timeout=30)
print(f"Webhook status: {resp.status_code}")
except Exception as wh_err:
print(f"Erro ao chamar webhook: {wh_err}")
ch.basic_ack(delivery_tag=method.delivery_tag)
def main():
def get_next_message():
credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS)
parameters = pika.ConnectionParameters(
host=RABBITMQ_HOST,
port=RABBITMQ_PORT,
credentials=credentials,
heartbeat=600,
heartbeat=60,
blocked_connection_timeout=300
)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
channel.queue_declare(queue=RABBITMQ_QUEUE, durable=True)
channel.basic_qos(prefetch_count=1)
channel.basic_consume(queue=RABBITMQ_QUEUE, on_message_callback=callback)
method_frame, header_frame, body = channel.basic_get(RABBITMQ_QUEUE)
if method_frame:
channel.basic_ack(method_frame.delivery_tag)
connection.close()
return body
else:
connection.close()
return None
def publish_to_queue(payload):
credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS)
parameters = pika.ConnectionParameters(
host=RABBITMQ_HOST,
port=RABBITMQ_PORT,
credentials=credentials,
heartbeat=60,
blocked_connection_timeout=300
)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
channel.queue_declare(queue=RABBITMQ_UPLOAD_QUEUE, durable=True)
channel.basic_publish(
exchange='',
routing_key=RABBITMQ_UPLOAD_QUEUE,
body=json.dumps(payload),
properties=pika.BasicProperties(
delivery_mode=2, # persistente
)
)
connection.close()
def main():
print(' [*] Esperando mensagens. Para sair: CTRL+C')
while True:
body = get_next_message()
if body is None:
time.sleep(5)
continue
channel.start_consuming()
try:
data = json.loads(body)
filename = data.get("filename")
times = data.get("times", [])
url = data.get("url")
video_id = data.get("videoId")
print(f"Processando vídeo: {filename}")
processed_files = process_full_video(filename, times)
payload = {
"videosProcessedQuantity": len(processed_files),
"filename": filename,
"processedFiles": processed_files,
"url": url,
"videoId": video_id,
"error": False,
}
except Exception as e:
payload = {
"videosProcessedQuantity": 0,
"filename": filename if 'filename' in locals() else None,
"processedFiles": [],
"url": url if 'url' in locals() else None,
"videoId": video_id if 'video_id' in locals() else None,
"error": str(e),
}
print(f"Erro no processamento: {e}")
try:
publish_to_queue(payload)
print(f"Mensagem publicada na fila '{RABBITMQ_UPLOAD_QUEUE}'.")
except Exception as publish_err:
print(f"Erro ao publicar na fila '{RABBITMQ_UPLOAD_QUEUE}': {publish_err}")
if __name__ == "__main__":
main()