Alide21 commited on
Commit
35b6f0b
·
verified ·
1 Parent(s): 435489e

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +40 -57
main.py CHANGED
@@ -12,16 +12,18 @@ from flask import Flask, jsonify
12
  STREAM_KEY = os.environ.get("STREAM_KEY")
13
  STREAM_URL = "rtmp://a.rtmp.youtube.com/live2/"
14
  BG_IMAGE = "https://images.unsplash.com/photo-1555400038-63f5ba517a47?q=80&w=1920&auto=format&fit=crop"
15
- # رابط صوت عقارب ساعة (Tick Tock)
16
- TICK_SOUND_URL = "https://cdn.pixabay.com/audio/2022/03/10/audio_c23a7c6156.mp3"
 
17
 
18
  app = Flask(__name__)
19
 
20
- # دالة ذكية لتحديد الحالة (عد تنازلي / رمضان / عيد / السنة القادمة)
 
 
21
  def get_current_status():
22
  try:
23
- # 1. جلب التاريخ الهجري الحالي
24
- # نستخدم التقويم الهجري لتحديد المناسبات بدقة
25
  res = requests.get("http://api.aladhan.com/v1/timingsByCity?city=Mecca&country=SA&method=4", timeout=5)
26
  data = res.json()['data']
27
 
@@ -31,41 +33,33 @@ def get_current_status():
31
  h_year = int(hijri_date['year'])
32
  date_str = hijri_date['date']
33
 
34
- # تحديد التواريخ المفصلية
35
- # رمضان = الشهر 9
36
- # عيد الفطر = الشهر 10 (شوال)، ويستمر 3 أيام (من 1 إلى 3 شوال)
37
-
38
  status = ""
39
  target_date_gregorian = None
40
  msg = ""
41
 
42
- # الحالة 1: نحن في شهر رمضان (من 1 رمضان إلى 30 رمضان)
43
  if h_month == 9:
44
  status = "ramadan_live"
45
  msg = "جاء رمضان.. مبارك عليكم الشهر"
46
 
47
- # الحالة 2: نحن في عيد الفطر (من 1 شوال إلى 3 شوال)
48
  elif h_month == 10 and h_day <= 3:
49
  status = "eid_live"
50
  msg = "عيد مبارك - كل عام وأنتم بخير"
51
 
52
- # الحالة 3: قبل رمضان (من شوال 4 إلى شعبان) أو بعد العيد مباشرة
53
  else:
54
  status = "counting"
55
  # حساب موعد رمضان القادم
56
- # إذا كنا قبل رمضان في نفس السنة (الأشهر 1-8) -> رمضان هذا العام
57
  if h_month < 9:
58
- target_h_year = h_year
59
- # إذا كنا بعد رمضان والعيد (أواخر شهر 10 أو الأشهر 11-12) -> رمضان العام القادم
60
  else:
61
- target_h_year = h_year + 1
62
 
63
- # نحتاج تحويل 1 رمضان لسنة المستهدفة) إلى ميلادي لحساب الفرق
64
- # نستخدم API التحويل من Aladhan
65
  conv_res = requests.get(f"http://api.aladhan.com/v1/hToG?date=01-09-{target_h_year}", timeout=5)
66
  g_data = conv_res.json()['data']['gregorian']
67
 
68
- # صيغة التاريخ من الـ API تكون DD-MM-YYYY
69
  target_date_str = g_data['date']
70
  target_date_gregorian = datetime.strptime(target_date_str, "%d-%m-%Y")
71
 
@@ -78,12 +72,12 @@ def get_current_status():
78
 
79
  except Exception as e:
80
  print(f"API Error: {e}")
81
- # قيمة افتراضية في حال تعطل الـ API (تاريخ يدوي احتياطي)
82
  return {
83
  "status": "counting",
84
  "msg": "",
85
- "hijri_str": "جاري التحديث...",
86
- "target_date": datetime(2026, 2, 19, 0, 0, 0)
87
  }
88
 
89
  @app.route('/time_data')
@@ -97,14 +91,12 @@ def time_data():
97
  "hijri": current_state['hijri_str']
98
  })
99
 
100
- # حساب العد التنازلي
101
  now = datetime.now()
102
  if current_state['target_date']:
103
  diff = current_state['target_date'] - now
104
  else:
105
  diff = timedelta(0)
106
 
107
- # إذا انتهى الوقت ولم تلتقط الحالة بعد (لأجزاء من الثانية)
108
  if diff.total_seconds() <= 0:
109
  return jsonify({"status": "loading", "msg": "جاري التحديث...", "hijri": current_state['hijri_str']})
110
 
@@ -121,6 +113,9 @@ def time_data():
121
  "hijri": current_state['hijri_str']
122
  })
123
 
 
 
 
124
  @app.route('/')
125
  def home():
126
  html_content = """
@@ -142,8 +137,8 @@ def home():
142
  .hijri-badge { background: #4CAF50; padding: 5px 20px; border-radius: 50px; font-size: 20px; margin-bottom: 20px; display: inline-block; }
143
  .title { font-size: 40px; margin-bottom: 30px; text-shadow: 2px 2px 10px rgba(0,0,0,0.8); }
144
 
145
- /* تعديل الـ Flex ليشمل النقطتين */
146
- .countdown { display: flex; gap: 10px; justify-content: center; direction: ltr; align-items: start; }
147
 
148
  .card {
149
  background: linear-gradient(180deg, #4CAF50, #2E7D32);
@@ -155,15 +150,13 @@ def home():
155
  .unit { display: flex; flex-direction: column; align-items: center; }
156
  .label { margin-top: 8px; font-size: 18px; color: #4CAF50; font-weight: bold; }
157
 
158
- /* ستايل النقطتين الفاصلة */
159
  .colon {
160
  font-size: 70px;
161
  color: #4CAF50;
162
  font-weight: 900;
163
- margin-top: 20px; /* محاذاة مع الأرقام */
164
- animation: blink 1s infinite;
165
  }
166
- @keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.3; } 100% { opacity: 1; } }
167
 
168
  #celebration { display: none; font-size: 60px; color: #FFD700; animation: pulse 2s infinite; }
169
  @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }
@@ -215,82 +208,72 @@ def home():
215
  """
216
  return html_content
217
 
 
 
 
218
  def start_stream():
219
  if not STREAM_KEY:
220
  print("Error: STREAM_KEY not found.")
221
  return
222
 
223
  while True:
224
- # جلب البيانات لتحديث FFmpeg
225
  current_state = get_current_status()
226
 
227
- # تحديد النصوص والألوان بناءً على الحالة
228
  if current_state['status'] == 'ramadan_live':
229
- # حالة رمضان
230
- display_text = "Ramadan Mubarak - Mubarak Alaykum Al-Shahr" # نص إنجليزي لضمان ظهوره في FFmpeg
231
- box_color = "0xD4AF37" # ذهبي
232
  title_text = "RAMADAN KAREEM"
233
  font_size = "65"
234
 
235
  elif current_state['status'] == 'eid_live':
236
- # حالة العيد
237
  display_text = "Eid Mubarak"
238
- box_color = "0x9C27B0" # بنفسجي للعيد
239
  title_text = "EID AL-FITR"
240
  font_size = "90"
241
 
242
  else:
243
- # حالة العد التنازلي
244
- # حساب الثواني المتبقية للتاريخ المستهدف
245
  if current_state['target_date']:
246
  target_ts = int(current_state['target_date'].timestamp())
247
  else:
248
  target_ts = int(datetime.now().timestamp())
249
 
250
- # تمت إضافة النقطتين (:) في تنسيق النص
251
  display_text = f" %{{pts\\:localtime\\:{target_ts}\\:%d}} : %{{pts\\:localtime\\:{target_ts}\\:%H}} : %{{pts\\:localtime\\:{target_ts}\\:%M}} : %{{pts\\:localtime\\:{target_ts}\\:%S}} "
252
- box_color = "0x4CAF50" # أخضر
253
  title_text = "RAMADAN COUNTDOWN"
254
  font_size = "90"
255
 
256
  # أوامر FFmpeg
257
- # تم إضافة: -stream_loop -1 -i TICK_SOUND_URL لإضافة صوت الساعة
258
  ffmpeg_cmd = [
259
  'ffmpeg',
260
  '-re',
261
- '-stream_loop', '-1', '-i', TICK_SOUND_URL, # مدخل الصوت (رقم 0)
262
- '-loop', '1', '-i', BG_IMAGE, # مدخل الفيديو/الصورة (رقم 1)
263
- '-map', '1:v', # استخدام الصورة للفيديو
264
- '-map', '0:a', # استخدام صوت الساعة للصوت
265
- '-f', 'lavfi', '-i', 'anullsrc', # صوت احتياطي صامت (لتجنب الأخطاء)
266
  '-vf', (
267
  f"scale=1280:720,setsar=1,"
268
  f"drawbox=y=ih/2-80:color=black@0.6:width=iw:height=200:t=fill,"
269
  f"drawtext=text='{current_state['hijri_str']}':x=50:y=50:fontsize=30:fontcolor=white:box=1:boxcolor=0x4CAF50@0.8,"
270
  f"drawtext=text='{title_text}':x=(w-text_w)/2:y=230:fontsize=40:fontcolor=white,"
271
- # النص هنا يحتوي على النقطتين كما تم تعريفه في display_text
272
  f"drawtext=text='{display_text}':x=(w-text_w)/2:y=(h-text_h)/2+50:fontsize={font_size}:fontcolor=white:box=1:boxcolor={box_color}@1:boxborderw=25"
273
  ),
274
  '-vcodec', 'libx264', '-preset', 'veryfast', '-b:v', '3000k', '-maxrate', '3000k', '-bufsize', '6000k',
275
  '-pix_fmt', 'yuv420p', '-g', '60',
276
- '-c:a', 'aac', '-b:a', '128k', # ترميز الصوت
277
- '-shortest', # إنهاء البث عند أقصر مدخل (لكننا نستخدم Loop فلا يهم كثيراً هنا)
278
  '-f', 'flv', f"{STREAM_URL}{STREAM_KEY}"
279
  ]
280
 
281
  try:
282
- # ملاحظة: سيستمر هذا الأمر بالعمل إلى أن تتغير الحالة،
283
- # ولكن نظراً لأن FFmpeg لا يدعم تغيير النصوص ديناميكياً بسهولة بدون إعادة التشغيل،
284
- # فإننا نعتمد على إعادة تشغيل الحلقة عند حدوث خطأ أو يمكننا جعل subprocess يغلق ويعيد الفتح
285
- # ولكن للأمان والبساطة سنتركه يعمل. التحديث الحقيقي للنص يتطلب إعادة تشغيل العملية.
286
- # في هذا الكود، سيتم تحديث النص فقط إذا انقطع البث وأعاد الاتصال.
287
  subprocess.run(ffmpeg_cmd, check=True)
288
  except Exception as e:
289
  print(f"Stream error/restart: {e}")
290
  time.sleep(5)
291
 
292
  if __name__ == "__main__":
293
- # تشغيل سيرفر الويب في خلفية مستقلة
294
  threading.Thread(target=lambda: app.run(host='0.0.0.0', port=7860, debug=False, use_reloader=False), daemon=True).start()
295
- # بدء البث المباشر
296
  start_stream()
 
12
  STREAM_KEY = os.environ.get("STREAM_KEY")
13
  STREAM_URL = "rtmp://a.rtmp.youtube.com/live2/"
14
  BG_IMAGE = "https://images.unsplash.com/photo-1555400038-63f5ba517a47?q=80&w=1920&auto=format&fit=crop"
15
+
16
+ # اسم الملف الصوتي المرفوع على الـ Space
17
+ TICK_SOUND_FILE = "time.mp3"
18
 
19
  app = Flask(__name__)
20
 
21
+ # ==========================================
22
+ # منطق تحديد الوقت والحالة (رمضان/عيد/عد تنازلي)
23
+ # ==========================================
24
  def get_current_status():
25
  try:
26
+ # جلب التاريخ الهجري الحالي بدقة
 
27
  res = requests.get("http://api.aladhan.com/v1/timingsByCity?city=Mecca&country=SA&method=4", timeout=5)
28
  data = res.json()['data']
29
 
 
33
  h_year = int(hijri_date['year'])
34
  date_str = hijri_date['date']
35
 
 
 
 
 
36
  status = ""
37
  target_date_gregorian = None
38
  msg = ""
39
 
40
+ # الحالة 1: نحن في شهر رمضان (الشهر 9)
41
  if h_month == 9:
42
  status = "ramadan_live"
43
  msg = "جاء رمضان.. مبارك عليكم الشهر"
44
 
45
+ # الحالة 2: نحن في عيد الفطر (الشهر 10، الأيام 1-3)
46
  elif h_month == 10 and h_day <= 3:
47
  status = "eid_live"
48
  msg = "عيد مبارك - كل عام وأنتم بخير"
49
 
50
+ # الحالة 3: العد التنازلي (قبل رمضان أو بعد العيد)
51
  else:
52
  status = "counting"
53
  # حساب موعد رمضان القادم
 
54
  if h_month < 9:
55
+ target_h_year = h_year # نفس السنة
 
56
  else:
57
+ target_h_year = h_year + 1 # السنة القادمة
58
 
59
+ # تحويل 1 رمضان للسنة المستهدفة إلى ميلادي
 
60
  conv_res = requests.get(f"http://api.aladhan.com/v1/hToG?date=01-09-{target_h_year}", timeout=5)
61
  g_data = conv_res.json()['data']['gregorian']
62
 
 
63
  target_date_str = g_data['date']
64
  target_date_gregorian = datetime.strptime(target_date_str, "%d-%m-%Y")
65
 
 
72
 
73
  except Exception as e:
74
  print(f"API Error: {e}")
75
+ # قيم افتراضية للحفاظ على استمرار البث عند الخطأ
76
  return {
77
  "status": "counting",
78
  "msg": "",
79
+ "hijri_str": "1447-09-01", # تاريخ تقريبي
80
+ "target_date": datetime(2026, 2, 18, 0, 0, 0) # تاريخ تقريبي
81
  }
82
 
83
  @app.route('/time_data')
 
91
  "hijri": current_state['hijri_str']
92
  })
93
 
 
94
  now = datetime.now()
95
  if current_state['target_date']:
96
  diff = current_state['target_date'] - now
97
  else:
98
  diff = timedelta(0)
99
 
 
100
  if diff.total_seconds() <= 0:
101
  return jsonify({"status": "loading", "msg": "جاري التحديث...", "hijri": current_state['hijri_str']})
102
 
 
113
  "hijri": current_state['hijri_str']
114
  })
115
 
116
+ # ==========================================
117
+ # صفحة الويب (HTML + CSS)
118
+ # ==========================================
119
  @app.route('/')
120
  def home():
121
  html_content = """
 
137
  .hijri-badge { background: #4CAF50; padding: 5px 20px; border-radius: 50px; font-size: 20px; margin-bottom: 20px; display: inline-block; }
138
  .title { font-size: 40px; margin-bottom: 30px; text-shadow: 2px 2px 10px rgba(0,0,0,0.8); }
139
 
140
+ /* تعديل المحاذاة لتكون في المنتصف تماماً */
141
+ .countdown { display: flex; gap: 10px; justify-content: center; direction: ltr; align-items: center; }
142
 
143
  .card {
144
  background: linear-gradient(180deg, #4CAF50, #2E7D32);
 
150
  .unit { display: flex; flex-direction: column; align-items: center; }
151
  .label { margin-top: 8px; font-size: 18px; color: #4CAF50; font-weight: bold; }
152
 
153
+ /* النقطتين: تم إزالة الوميض وضبط الارتفاع */
154
  .colon {
155
  font-size: 70px;
156
  color: #4CAF50;
157
  font-weight: 900;
158
+ padding-bottom: 10px; /* تعديل طفيف لضبط المحاذاة البصرية مع الأرقام */
 
159
  }
 
160
 
161
  #celebration { display: none; font-size: 60px; color: #FFD700; animation: pulse 2s infinite; }
162
  @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }
 
208
  """
209
  return html_content
210
 
211
+ # ==========================================
212
+ # دالة البث المباشر (FFmpeg)
213
+ # ==========================================
214
  def start_stream():
215
  if not STREAM_KEY:
216
  print("Error: STREAM_KEY not found.")
217
  return
218
 
219
  while True:
 
220
  current_state = get_current_status()
221
 
222
+ # إعدادات النصوص والألوان
223
  if current_state['status'] == 'ramadan_live':
224
+ display_text = "Ramadan Mubarak - Mubarak Alaykum Al-Shahr"
225
+ box_color = "0xD4AF37"
 
226
  title_text = "RAMADAN KAREEM"
227
  font_size = "65"
228
 
229
  elif current_state['status'] == 'eid_live':
 
230
  display_text = "Eid Mubarak"
231
+ box_color = "0x9C27B0"
232
  title_text = "EID AL-FITR"
233
  font_size = "90"
234
 
235
  else:
 
 
236
  if current_state['target_date']:
237
  target_ts = int(current_state['target_date'].timestamp())
238
  else:
239
  target_ts = int(datetime.now().timestamp())
240
 
 
241
  display_text = f" %{{pts\\:localtime\\:{target_ts}\\:%d}} : %{{pts\\:localtime\\:{target_ts}\\:%H}} : %{{pts\\:localtime\\:{target_ts}\\:%M}} : %{{pts\\:localtime\\:{target_ts}\\:%S}} "
242
+ box_color = "0x4CAF50"
243
  title_text = "RAMADAN COUNTDOWN"
244
  font_size = "90"
245
 
246
  # أوامر FFmpeg
247
+ # استخدام الملف المحلي time.mp3
248
  ffmpeg_cmd = [
249
  'ffmpeg',
250
  '-re',
251
+ '-stream_loop', '-1', '-i', TICK_SOUND_FILE, # استخدام الملف المحلي
252
+ '-loop', '1', '-i', BG_IMAGE,
253
+ '-map', '1:v',
254
+ '-map', '0:a',
255
+ '-f', 'lavfi', '-i', 'anullsrc',
256
  '-vf', (
257
  f"scale=1280:720,setsar=1,"
258
  f"drawbox=y=ih/2-80:color=black@0.6:width=iw:height=200:t=fill,"
259
  f"drawtext=text='{current_state['hijri_str']}':x=50:y=50:fontsize=30:fontcolor=white:box=1:boxcolor=0x4CAF50@0.8,"
260
  f"drawtext=text='{title_text}':x=(w-text_w)/2:y=230:fontsize=40:fontcolor=white,"
 
261
  f"drawtext=text='{display_text}':x=(w-text_w)/2:y=(h-text_h)/2+50:fontsize={font_size}:fontcolor=white:box=1:boxcolor={box_color}@1:boxborderw=25"
262
  ),
263
  '-vcodec', 'libx264', '-preset', 'veryfast', '-b:v', '3000k', '-maxrate', '3000k', '-bufsize', '6000k',
264
  '-pix_fmt', 'yuv420p', '-g', '60',
265
+ '-c:a', 'aac', '-b:a', '128k',
266
+ '-shortest',
267
  '-f', 'flv', f"{STREAM_URL}{STREAM_KEY}"
268
  ]
269
 
270
  try:
 
 
 
 
 
271
  subprocess.run(ffmpeg_cmd, check=True)
272
  except Exception as e:
273
  print(f"Stream error/restart: {e}")
274
  time.sleep(5)
275
 
276
  if __name__ == "__main__":
277
+ # تشغيل التطبيق والبث
278
  threading.Thread(target=lambda: app.run(host='0.0.0.0', port=7860, debug=False, use_reloader=False), daemon=True).start()
 
279
  start_stream()