post / renderer.py
ex510's picture
Upload 7 files
8f7c473 verified
"""
Video Renderer
المحرك المشترك بين كل التمبلتس
بياخد التمبلت + البيانات → بيعمل الفيديو
"""
import os
import subprocess
import tempfile
import shutil
from PIL import Image
from templates.base import RenderRequest
def download_font():
if not os.path.exists('/tmp/arabic.ttf'):
print('📥 تحميل الخط العربي...')
result = subprocess.run([
'wget', '-q', '-O', '/tmp/arabic.ttf',
'https://github.com/googlefonts/noto-fonts/raw/main/hinted/ttf/NotoNaskhArabic/NotoNaskhArabic-Bold.ttf'
], capture_output=True)
if result.returncode == 0:
print('✅ الخط جاهز')
def render_video(template, req: RenderRequest) -> str:
"""
بياخد التمبلت + الـ request
بيرجع مسار الفيديو النهائي
"""
download_font()
W, H = req.width, req.height
fps = req.fps
total = req.duration * fps
tmp = tempfile.mkdtemp()
# تحميل الصور
product_img = None
if req.image_path and os.path.exists(req.image_path):
product_img = Image.open(req.image_path).convert('RGBA')
logo_img = None
# رسم الـ frames
print(f'🎬 [{template.NAME}] بيرسم {total} frame...')
for i in range(total):
t = i / fps
frame = template.make_frame(t, req, product_img, logo_img)
frame.save(os.path.join(tmp, f'frame_{i:05d}.png'))
if i % fps == 0:
print(f' {i//fps}/{req.duration} ثانية')
# FFmpeg — بيعمل الفيديو
video_raw = os.path.join(tmp, 'raw.mp4')
print('🎞️ FFmpeg...')
subprocess.run([
'ffmpeg', '-y',
'-framerate', str(fps),
'-i', os.path.join(tmp, 'frame_%05d.png'),
'-c:v', 'libx264',
'-pix_fmt', 'yuv420p',
'-crf', '18',
'-movflags', '+faststart',
video_raw
], capture_output=True)
# إضافة الموسيقى
final = req.output_path
if req.music_path and os.path.exists(req.music_path):
print('🎵 بيضيف الموسيقى...')
result = subprocess.run([
'ffmpeg', '-y',
'-i', video_raw,
'-i', req.music_path,
'-filter_complex',
f'[1:a]volume={req.music_volume},'
f'afade=t=in:st=0:d=1,'
f'afade=t=out:st=4:d=2[m];[m]apad[audio]',
'-map', '0:v',
'-map', '[audio]',
'-shortest',
'-c:v', 'copy',
'-c:a', 'aac',
'-b:a', '192k',
final
], capture_output=True, text=True)
if result.returncode != 0:
shutil.copy(video_raw, final)
else:
shutil.copy(video_raw, final)
shutil.rmtree(tmp)
return final