File size: 2,851 Bytes
8f7c473 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | """
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
|