Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
-
|
|
|
|
|
|
|
| 3 |
import arabic_reshaper
|
| 4 |
from bidi.algorithm import get_display
|
| 5 |
import random
|
|
@@ -8,75 +10,69 @@ import os
|
|
| 8 |
# إعداد الصفحة
|
| 9 |
st.set_page_config(page_title="AutoQuotesVideo", page_icon="🎬")
|
| 10 |
|
| 11 |
-
# قائمة الحكم
|
| 12 |
QUOTES = [
|
| 13 |
"الخيل والليل والبيداء تعرفني والسيف والرمح والقرطاس والقلم",
|
| 14 |
"الوقت كالسيف إن لم تقطعه قطعك",
|
| 15 |
"من جد وجد ومن زرع حصد",
|
| 16 |
"العلم يرفع بيتاً لا عماد له والجهل يهدم بيت العز والكرم",
|
| 17 |
-
"كن عالماً في الناس أو متعلمًا أو سامعاً فالعلم ثوب فخار",
|
| 18 |
"لا تحسبن المجد تمراً أنت آكله لن تبلغ المجد حتى تلعق الصبرا"
|
| 19 |
]
|
| 20 |
|
| 21 |
-
def
|
| 22 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
reshaped_text = arabic_reshaper.reshape(text)
|
| 24 |
bidi_text = get_display(reshaped_text)
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
| 30 |
|
| 31 |
-
# م
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
# 1. الخلفية
|
| 35 |
-
bg_color = random.choice([(
|
| 36 |
background = ColorClip(size=size, color=bg_color).set_duration(duration)
|
| 37 |
|
| 38 |
-
# 2.
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
text_clip = TextClip(
|
| 42 |
-
display_text,
|
| 43 |
-
fontsize=60,
|
| 44 |
-
color='white',
|
| 45 |
-
font='DejaVu-Sans', # خط يدعم العربية متاح في لينكس
|
| 46 |
-
method='caption',
|
| 47 |
-
size=(640, None)
|
| 48 |
-
).set_position('center').set_duration(duration)
|
| 49 |
-
except Exception as e:
|
| 50 |
-
st.error(f"خطأ في توليد النص: {e}")
|
| 51 |
-
return None
|
| 52 |
-
|
| 53 |
-
# 3. دمج الفيديو
|
| 54 |
-
video = CompositeVideoClip([background, text_clip])
|
| 55 |
|
| 56 |
-
#
|
|
|
|
| 57 |
video.write_videofile(output_path, fps=24, codec="libx264", audio=False)
|
| 58 |
return output_path
|
| 59 |
|
| 60 |
-
|
| 61 |
-
st.
|
| 62 |
-
st.info("هذا التطبيق يقوم بإنشاء فيديو قصير (Reels) يحتوي على حكمة عربية عشوائية.")
|
| 63 |
|
| 64 |
if st.button("🚀 إنشاء فيديو الآن"):
|
| 65 |
quote = random.choice(QUOTES)
|
| 66 |
-
st.
|
| 67 |
-
|
| 68 |
-
with st.spinner("انتظر قليلاً.. جاري معالجة الفيديو..."):
|
| 69 |
try:
|
| 70 |
output = create_video(quote)
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
st.download_button("⬇️ تحميل الفيديو", f, file_name="quote_video.mp4")
|
| 75 |
-
else:
|
| 76 |
-
st.error("فشل إنشاء الفيديو.")
|
| 77 |
except Exception as e:
|
| 78 |
-
st.error(f"
|
| 79 |
-
|
| 80 |
-
st.markdown("---")
|
| 81 |
-
st.caption("تم التطوير بواسطة عمار الخطيب - INEX")
|
| 82 |
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
+
import numpy as np
|
| 3 |
+
from moviepy.editor import ImageClip, ColorClip, CompositeVideoClip
|
| 4 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 5 |
import arabic_reshaper
|
| 6 |
from bidi.algorithm import get_display
|
| 7 |
import random
|
|
|
|
| 10 |
# إعداد الصفحة
|
| 11 |
st.set_page_config(page_title="AutoQuotesVideo", page_icon="🎬")
|
| 12 |
|
|
|
|
| 13 |
QUOTES = [
|
| 14 |
"الخيل والليل والبيداء تعرفني والسيف والرمح والقرطاس والقلم",
|
| 15 |
"الوقت كالسيف إن لم تقطعه قطعك",
|
| 16 |
"من جد وجد ومن زرع حصد",
|
| 17 |
"العلم يرفع بيتاً لا عماد له والجهل يهدم بيت العز والكرم",
|
|
|
|
| 18 |
"لا تحسبن المجد تمراً أنت آكله لن تبلغ المجد حتى تلعق الصبرا"
|
| 19 |
]
|
| 20 |
|
| 21 |
+
def create_text_image(text, size=(720, 1280), font_size=50):
|
| 22 |
+
# إنشاء صورة شفافة للنص باستخدام Pillow بدلاً من ImageMagick
|
| 23 |
+
img = Image.new('RGBA', size, (0, 0, 0, 0))
|
| 24 |
+
draw = ImageDraw.Draw(img)
|
| 25 |
+
|
| 26 |
+
# معالجة النص العربي
|
| 27 |
reshaped_text = arabic_reshaper.reshape(text)
|
| 28 |
bidi_text = get_display(reshaped_text)
|
| 29 |
+
|
| 30 |
+
# محاولة تحميل خط يدعم العربية (موجود افتراضياً في Debian/Ubuntu)
|
| 31 |
+
try:
|
| 32 |
+
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", font_size)
|
| 33 |
+
except:
|
| 34 |
+
font = ImageFont.load_default()
|
| 35 |
|
| 36 |
+
# حساب موقع النص ليكون في المنتصف
|
| 37 |
+
left, top, right, bottom = draw.textbbox((0, 0), bidi_text, font=font)
|
| 38 |
+
w, h = right - left, bottom - top
|
| 39 |
+
x = (size[0] - w) / 2
|
| 40 |
+
y = (size[1] - h) / 2
|
| 41 |
|
| 42 |
+
# رسم النص بلون ذهبي مع ظل خفيف
|
| 43 |
+
draw.text((x+2, y+2), bidi_text, font=font, fill=(0, 0, 0, 128)) # Shadow
|
| 44 |
+
draw.text((x, y), bidi_text, font=font, fill=(255, 215, 0, 255)) # Gold
|
| 45 |
+
|
| 46 |
+
return np.array(img)
|
| 47 |
+
|
| 48 |
+
def create_video(quote_text, output_path="output_video.mp4"):
|
| 49 |
+
duration = 5
|
| 50 |
+
size = (720, 1280)
|
| 51 |
|
| 52 |
# 1. الخلفية
|
| 53 |
+
bg_color = random.choice([(15, 32, 39), (44, 62, 80), (20, 20, 20)])
|
| 54 |
background = ColorClip(size=size, color=bg_color).set_duration(duration)
|
| 55 |
|
| 56 |
+
# 2. توليد صورة النص
|
| 57 |
+
text_array = create_text_image(quote_text, size=size)
|
| 58 |
+
text_clip = ImageClip(text_array).set_duration(duration).set_position('center')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
+
# 3. الدمج
|
| 61 |
+
video = CompositeVideoClip([background, text_clip])
|
| 62 |
video.write_videofile(output_path, fps=24, codec="libx264", audio=False)
|
| 63 |
return output_path
|
| 64 |
|
| 65 |
+
st.title("🎥 مولد فيديوهات الحكم - نسخة الـ Docker المستقرة")
|
| 66 |
+
st.info("تم تحديث الكود ليعمل بدون الحاجة لـ ImageMagick لتجنب أخطاء البناء.")
|
|
|
|
| 67 |
|
| 68 |
if st.button("🚀 إنشاء فيديو الآن"):
|
| 69 |
quote = random.choice(QUOTES)
|
| 70 |
+
with st.spinner("جاري إنشاء الفيديو..."):
|
|
|
|
|
|
|
| 71 |
try:
|
| 72 |
output = create_video(quote)
|
| 73 |
+
st.video(output)
|
| 74 |
+
with open(output, "rb") as f:
|
| 75 |
+
st.download_button("⬇️ تحميل الفيديو", f, file_name="quote.mp4")
|
|
|
|
|
|
|
|
|
|
| 76 |
except Exception as e:
|
| 77 |
+
st.error(f"خطأ: {e}")
|
|
|
|
|
|
|
|
|
|
| 78 |
|