Alide21 commited on
Commit
8d380e3
·
verified ·
1 Parent(s): 3ef04bd

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +174 -70
main.py CHANGED
@@ -3,57 +3,123 @@ import time
3
  import subprocess
4
  import threading
5
  import requests
6
- from datetime import datetime
7
  from flask import Flask, jsonify
8
 
9
  # ==========================================
10
  # الإعدادات الأساسية
11
  # ==========================================
12
- TARGET_DATE = datetime(2026, 2, 19, 0, 0, 0) # موعد رمضان المتوقع
13
  STREAM_KEY = os.environ.get("STREAM_KEY")
14
  STREAM_URL = "rtmp://a.rtmp.youtube.com/live2/"
15
  BG_IMAGE = "https://images.unsplash.com/photo-1555400038-63f5ba517a47?q=80&w=1920&auto=format&fit=crop"
 
 
16
 
17
  app = Flask(__name__)
18
 
19
- # دالة لجلب البيانات من الـ API أو الحساب المحلي
20
- def get_detailed_data():
21
- now = datetime.now()
22
- hijri_date = ""
23
  try:
24
- # جلب التاريخ الهجري من API (توقيت مكة)
25
- res = requests.get("http://api.aladhan.com/v1/timingsByCity?city=Mecca&country=SA", timeout=5)
26
- if res.status_code == 200:
27
- hijri_date = res.json()['data']['date']['hijri']['date']
28
- except:
29
- hijri_date = "جاري التحديث..."
30
-
31
- diff = TARGET_DATE - now
32
- if diff.total_seconds() <= 0:
33
- return {"status": "finished", "msg": "جاء رمضان.. مبارك عليكم الشهر", "hijri": hijri_date}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
 
 
 
 
 
 
 
 
 
 
 
35
  days = diff.days
36
  hours, rem = divmod(diff.seconds, 3600)
37
  minutes, seconds = divmod(rem, 60)
38
 
39
- return {
40
  "status": "counting",
41
  "days": f"{days:02}",
42
  "hours": f"{hours:02}",
43
  "minutes": f"{minutes:02}",
44
  "seconds": f"{seconds:02}",
45
- "hijri": hijri_date
46
- }
47
-
48
- @app.route('/time_data')
49
- def time_data():
50
- data = get_detailed_data()
51
- # إضافة النقطتين بين الوحدات
52
- if data['status'] == 'counting':
53
- data['formatted'] = f"{data['days']} : {data['hours']} : {data['minutes']} : {data['seconds']}"
54
- else:
55
- data['formatted'] = data['msg']
56
- return jsonify(data)
57
 
58
  @app.route('/')
59
  def home():
@@ -62,7 +128,7 @@ def home():
62
  <html lang="ar" dir="rtl">
63
  <head>
64
  <meta charset="UTF-8">
65
- <title>بث مباشر | رمضان 2026</title>
66
  <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@700;900&display=swap" rel="stylesheet">
67
  <style>
68
  body { background-color: #0f0f0f; color: white; font-family: 'Cairo', sans-serif; margin: 0; overflow: hidden; }
@@ -75,7 +141,10 @@ def home():
75
  .content { z-index: 10; text-align: center; width: 100%; }
76
  .hijri-badge { background: #4CAF50; padding: 5px 20px; border-radius: 50px; font-size: 20px; margin-bottom: 20px; display: inline-block; }
77
  .title { font-size: 40px; margin-bottom: 30px; text-shadow: 2px 2px 10px rgba(0,0,0,0.8); }
78
- .countdown { display: flex; gap: 5px; justify-content: center; direction: ltr; align-items: center; }
 
 
 
79
  .card {
80
  background: linear-gradient(180deg, #4CAF50, #2E7D32);
81
  width: 110px; height: 140px; border-radius: 15px;
@@ -83,11 +152,19 @@ def home():
83
  justify-content: center; align-items: center;
84
  box-shadow: 0 8px 15px rgba(0,0,0,0.5);
85
  }
86
- .colon {
87
- font-size: 80px; font-weight: 900; color: #4CAF50;
88
- margin: 0 10px; line-height: 140px;
 
 
 
 
 
 
 
89
  }
90
- .label { margin-top: 8px; font-size: 18px; color: #4CAF50; font-weight: bold; text-align: center; }
 
91
  #celebration { display: none; font-size: 60px; color: #FFD700; animation: pulse 2s infinite; }
92
  @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }
93
  </style>
@@ -98,30 +175,18 @@ def home():
98
  <div class="content">
99
  <div class="hijri-badge" id="hijri-top">--/--/----</div>
100
  <div id="main-ui">
101
- <div class="title">الوقت المتبقي على شهر رمضان 2026</div>
102
  <div class="countdown">
103
- <div class="unit">
104
- <div class="card" id="days">00</div>
105
- <div class="label">أيام</div>
106
- </div>
107
  <div class="colon">:</div>
108
- <div class="unit">
109
- <div class="card" id="hours">00</div>
110
- <div class="label">ساعات</div>
111
- </div>
112
  <div class="colon">:</div>
113
- <div class="unit">
114
- <div class="card" id="minutes">00</div>
115
- <div class="label">دقائق</div>
116
- </div>
117
  <div class="colon">:</div>
118
- <div class="unit">
119
- <div class="card" id="seconds">00</div>
120
- <div class="label">ثواني</div>
121
- </div>
122
  </div>
123
  </div>
124
- <div id="celebration">قد جاء رمضان.. مبارك عليكم الشهر</div>
125
  </div>
126
  </div>
127
  <script>
@@ -130,8 +195,11 @@ def home():
130
  document.getElementById('hijri-top').innerText = data.hijri;
131
  if(data.status === 'finished') {
132
  document.getElementById('main-ui').style.display = 'none';
 
133
  document.getElementById('celebration').style.display = 'block';
134
  } else {
 
 
135
  document.getElementById('days').innerText = data.days;
136
  document.getElementById('hours').innerText = data.hours;
137
  document.getElementById('minutes').innerText = data.minutes;
@@ -153,36 +221,72 @@ def start_stream():
153
  return
154
 
155
  while True:
156
- data = get_detailed_data()
157
- target_ts = int(TARGET_DATE.timestamp())
158
 
159
- # إعداد النص ليوتيوب مع النقطتين
160
- if data['status'] == 'finished':
161
- display_text = "RAMADAN KAREEM - MUBARAK"
162
- box_color = "0xD4AF37" # ذهبي للعيد/رمضان
 
 
 
 
 
 
 
 
 
 
 
163
  else:
164
- # تنسيق العداد مع النقطتين: أيام : ساعات : دقائق : ثواني
165
- display_text = f" {data['days']} : {data['hours']} : {data['minutes']} : {data['seconds']} "
166
- box_color = "0x4CAF50" # أخضر للانتظار
 
 
 
 
 
 
 
 
 
167
 
 
 
168
  ffmpeg_cmd = [
169
- 'ffmpeg', '-re', '-loop', '1', '-i', BG_IMAGE,
170
- '-f', 'lavfi', '-i', "aevalsrc=sin(440*2*PI*t)*0.1:enable='mod(t,1)'", # صوت تيك توك كل ثانية
 
 
 
 
 
171
  '-vf', (
172
  f"scale=1280:720,setsar=1,"
173
- f"drawbox=y=ih/2-80:color=black@0.6:width=iw:height=200:t=fill," # خلفية العداد
174
- f"drawtext=text='{data['hijri']}':x=50:y=50:fontsize=30:fontcolor=white:box=1:boxcolor=0x4CAF50@0.8," # التاريخ الهجري
175
- f"drawtext=text='RAMADAN 2026 COUNTDOWN':x=(w-text_w)/2:y=230:fontsize=40:fontcolor=white,"
176
- f"drawtext=text='{display_text}':x=(w-text_w)/2:y=(h-text_h)/2+50:fontsize=90:fontcolor=white:box=1:boxcolor={box_color}@1:boxborderw=25"
 
177
  ),
178
  '-vcodec', 'libx264', '-preset', 'veryfast', '-b:v', '3000k', '-maxrate', '3000k', '-bufsize', '6000k',
179
- '-pix_fmt', 'yuv420p', '-g', '60', '-f', 'flv', f"{STREAM_URL}{STREAM_KEY}"
 
 
 
180
  ]
181
 
182
  try:
 
 
 
 
 
183
  subprocess.run(ffmpeg_cmd, check=True)
184
  except Exception as e:
185
- print(f"Stream error: {e}")
186
  time.sleep(5)
187
 
188
  if __name__ == "__main__":
 
3
  import subprocess
4
  import threading
5
  import requests
6
+ from datetime import datetime, timedelta
7
  from flask import Flask, jsonify
8
 
9
  # ==========================================
10
  # الإعدادات الأساسية
11
  # ==========================================
 
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
+
28
+ hijri_date = data['date']['hijri']
29
+ h_day = int(hijri_date['day'])
30
+ h_month = int(hijri_date['month']['number'])
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
+
72
+ return {
73
+ "status": status,
74
+ "msg": msg,
75
+ "hijri_str": date_str,
76
+ "target_date": target_date_gregorian
77
+ }
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')
90
+ def time_data():
91
+ current_state = get_current_status()
92
+
93
+ if current_state['status'] in ['ramadan_live', 'eid_live']:
94
+ return jsonify({
95
+ "status": "finished",
96
+ "msg": current_state['msg'],
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
+
111
  days = diff.days
112
  hours, rem = divmod(diff.seconds, 3600)
113
  minutes, seconds = divmod(rem, 60)
114
 
115
+ return jsonify({
116
  "status": "counting",
117
  "days": f"{days:02}",
118
  "hours": f"{hours:02}",
119
  "minutes": f"{minutes:02}",
120
  "seconds": f"{seconds:02}",
121
+ "hijri": current_state['hijri_str']
122
+ })
 
 
 
 
 
 
 
 
 
 
123
 
124
  @app.route('/')
125
  def home():
 
128
  <html lang="ar" dir="rtl">
129
  <head>
130
  <meta charset="UTF-8">
131
+ <title>بث مباشر | رمضان</title>
132
  <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@700;900&display=swap" rel="stylesheet">
133
  <style>
134
  body { background-color: #0f0f0f; color: white; font-family: 'Cairo', sans-serif; margin: 0; overflow: hidden; }
 
141
  .content { z-index: 10; text-align: center; width: 100%; }
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);
150
  width: 110px; height: 140px; border-radius: 15px;
 
152
  justify-content: center; align-items: center;
153
  box-shadow: 0 8px 15px rgba(0,0,0,0.5);
154
  }
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); } }
170
  </style>
 
175
  <div class="content">
176
  <div class="hijri-badge" id="hijri-top">--/--/----</div>
177
  <div id="main-ui">
178
+ <div class="title">الوقت المتبقي على شهر رمضان</div>
179
  <div class="countdown">
180
+ <div class="unit"><div class="card" id="days">00</div><div class="label">أيام</div></div>
 
 
 
181
  <div class="colon">:</div>
182
+ <div class="unit"><div class="card" id="hours">00</div><div class="label">ساعة</div></div>
 
 
 
183
  <div class="colon">:</div>
184
+ <div class="unit"><div class="card" id="minutes">00</div><div class="label">دقيقة</div></div>
 
 
 
185
  <div class="colon">:</div>
186
+ <div class="unit"><div class="card" id="seconds">00</div><div class="label">ثانية</div></div>
 
 
 
187
  </div>
188
  </div>
189
+ <div id="celebration">...</div>
190
  </div>
191
  </div>
192
  <script>
 
195
  document.getElementById('hijri-top').innerText = data.hijri;
196
  if(data.status === 'finished') {
197
  document.getElementById('main-ui').style.display = 'none';
198
+ document.getElementById('celebration').innerText = data.msg;
199
  document.getElementById('celebration').style.display = 'block';
200
  } else {
201
+ document.getElementById('main-ui').style.display = 'block';
202
+ document.getElementById('celebration').style.display = 'none';
203
  document.getElementById('days').innerText = data.days;
204
  document.getElementById('hours').innerText = data.hours;
205
  document.getElementById('minutes').innerText = data.minutes;
 
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__":