Alide21 commited on
Commit
ba11121
·
verified ·
1 Parent(s): 7b15c57

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +189 -106
main.py CHANGED
@@ -3,115 +3,170 @@ 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
- return jsonify(get_detailed_data())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  @app.route('/')
53
  def home():
54
- # كود الـ HTML مفصل تماماً عن الـ f-string لتجنب أخطاء Syntax
55
- html_content = """
56
  <!DOCTYPE html>
57
  <html lang="ar" dir="rtl">
58
  <head>
59
  <meta charset="UTF-8">
60
- <title>بث مباشر | رمضان 2026</title>
61
  <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@700;900&display=swap" rel="stylesheet">
62
  <style>
63
- body { background-color: #0f0f0f; color: white; font-family: 'Cairo', sans-serif; margin: 0; overflow: hidden; }
64
- .video-player {
65
- position: relative; width: 100vw; height: 100vh;
66
- background: url('""" + BG_IMAGE + """') no-repeat center center;
67
- background-size: cover; display: flex; flex-direction: column; justify-content: center; align-items: center;
68
- }
69
- .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }
70
- .content { z-index: 10; text-align: center; width: 100%; }
71
- .hijri-badge { background: #4CAF50; padding: 5px 20px; border-radius: 50px; font-size: 20px; margin-bottom: 20px; display: inline-block; }
72
- .title { font-size: 40px; margin-bottom: 30px; text-shadow: 2px 2px 10px rgba(0,0,0,0.8); }
73
- .countdown { display: flex; gap: 15px; justify-content: center; direction: ltr; }
74
- .card {
75
- background: linear-gradient(180deg, #4CAF50, #2E7D32);
76
- width: 110px; height: 140px; border-radius: 15px;
77
- font-size: 70px; font-weight: 900; display: flex;
78
- justify-content: center; align-items: center;
79
- box-shadow: 0 8px 15px rgba(0,0,0,0.5);
80
- }
81
- .label { margin-top: 8px; font-size: 18px; color: #4CAF50; font-weight: bold; }
82
- #celebration { display: none; font-size: 60px; color: #FFD700; animation: pulse 2s infinite; }
83
- @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }
84
  </style>
85
  </head>
86
  <body>
87
- <div class="video-player">
88
- <div class="overlay"></div>
89
- <div class="content">
90
- <div class="hijri-badge" id="hijri-top">--/--/----</div>
91
- <div id="main-ui">
92
- <div class="title">الوقت المتبقي على شهر رمضان 2026</div>
93
- <div class="countdown">
94
- <div class="unit"><div class="card" id="days">00</div><div class="label">أيام</div></div>
95
- <div class="unit"><div class="card" id="hours">00</div><div class="label">ساعة</div></div>
96
- <div class="unit"><div class="card" id="minutes">00</div><div class="label">دقيقة</div></div>
97
- <div class="unit"><div class="card" id="seconds">00</div><div class="label">ثانية</div></div>
98
- </div>
99
- </div>
100
- <div id="celebration">قد جاء رمضان.. مبارك عليكم الشهر</div>
101
  </div>
102
  </div>
 
 
 
103
  <script>
104
  function update() {
105
- fetch('/time_data').then(res => res.json()).then(data => {
106
- document.getElementById('hijri-top').innerText = data.hijri;
107
- if(data.status === 'finished') {
108
- document.getElementById('main-ui').style.display = 'none';
109
- document.getElementById('celebration').style.display = 'block';
 
 
 
110
  } else {
111
- document.getElementById('days').innerText = data.days;
112
- document.getElementById('hours').innerText = data.hours;
113
- document.getElementById('minutes').innerText = data.minutes;
114
- document.getElementById('seconds').innerText = data.seconds;
 
115
  }
116
  });
117
  }
@@ -121,48 +176,76 @@ def home():
121
  </body>
122
  </html>
123
  """
124
- return html_content
125
 
126
  def start_stream():
127
- if not STREAM_KEY:
128
- print("Error: STREAM_KEY not found.")
129
  return
130
 
131
  while True:
132
- data = get_detailed_data()
133
- target_ts = int(TARGET_DATE.timestamp())
134
 
135
- # إعداد النص ليوتيوب (بما أن FFmpeg لا يدعم العربية بسهولة، نستخدم الإنجليزية أو أرقام واضحة)
136
- if data['status'] == 'finished':
137
- display_text = "RAMADAN KAREEM - MUBARAK"
138
- box_color = "0xD4AF37" # ذهبي للعيد/رمضان
139
- else:
140
- # تنسيق العداد: أيام : ساعات : دقائق : ثواني
141
- display_text = f" %{{pts\\:localtime\\:{target_ts}\\:%d}}d : %{{H}}h : %{{M}}m : %{{S}}s "
142
- box_color = "0x4CAF50" # أخضر للانتظار
143
 
144
- ffmpeg_cmd = [
145
- 'ffmpeg', '-re', '-loop', '1', '-i', BG_IMAGE,
146
- '-f', 'lavfi', '-i', 'anullsrc',
147
- '-vf', (
 
 
 
 
 
 
 
 
 
 
148
  f"scale=1280:720,setsar=1,"
149
- f"drawbox=y=ih/2-80:color=black@0.6:width=iw:height=200:t=fill," # خلفية العداد
150
- f"drawtext=text='{data['hijri']}':x=50:y=50:fontsize=30:fontcolor=white:box=1:boxcolor=0x4CAF50@0.8," # التاريخ الهجري
151
- f"drawtext=text='RAMADAN 2026 COUNTDOWN':x=(w-text_w)/2:y=230:fontsize=40:fontcolor=white,"
152
- 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"
153
- ),
154
- '-vcodec', 'libx264', '-preset', 'veryfast', '-b:v', '3000k', '-maxrate', '3000k', '-bufsize', '6000k',
155
- '-pix_fmt', 'yuv420p', '-g', '60', '-f', 'flv', f"{STREAM_URL}{STREAM_KEY}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  ]
157
-
158
  try:
 
159
  subprocess.run(ffmpeg_cmd, check=True)
160
  except Exception as e:
161
- print(f"Stream error: {e}")
162
  time.sleep(5)
163
 
164
  if __name__ == "__main__":
165
- # تشغيل سيرفر الويب في خلفية مستقلة
166
  threading.Thread(target=lambda: app.run(host='0.0.0.0', port=7860, debug=False, use_reloader=False), daemon=True).start()
167
- # بدء البث المباشر
168
  start_stream()
 
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
+ # صور خلفية مختلفة لكل حالة (يمكنك تغيير الروابط)
15
+ BG_COUNTDOWN = "https://images.unsplash.com/photo-1555400038-63f5ba517a47?q=80&w=1920&auto=format&fit=crop" # خلفية العداد
16
+ BG_RAMADAN = "https://images.unsplash.com/photo-1542642832-d967f7a08151?q=80&w=1920&auto=format&fit=crop" # خلفية رمضان
17
+ BG_EID = "https://images.unsplash.com/photo-1519810755548-39213856a6a3?q=80&w=1920&auto=format&fit=crop" # خلفية العيد
18
 
19
  app = Flask(__name__)
20
 
21
+ # متغيرات عالمية لتخزين الحالة
22
+ current_status = "loading" # counting, ramadan, eid
23
+ target_date = None
24
+ hijri_date_str = "--/--/----"
25
+ last_api_update = 0
 
 
 
 
 
 
26
 
27
+ def update_timing_data():
28
+ """
29
+ دالة ذكية تحدد الحالة (عداد/رمضان/عيد) وتحسب التواريخ بناء على API
30
+ """
31
+ global target_date, current_status, hijri_date_str, last_api_update
 
 
32
 
33
+ # تحديث البيانات من الـ API كل ساعة لضمان عدم الضغط عليه
34
+ if time.time() - last_api_update < 3600 and target_date:
35
+ return
36
+
37
+ try:
38
+ # 1. جلب التاريخ الهجري الحالي
39
+ response = requests.get("http://api.aladhan.com/v1/timingsByCity?city=Mecca&country=SA")
40
+ data = response.json()['data']
41
+ hijri = data['date']['hijri']
42
+
43
+ h_day = int(hijri['day'])
44
+ h_month = int(hijri['month']['number'])
45
+ h_year = int(hijri['year'])
46
+ hijri_date_str = hijri['date']
47
+
48
+ # 2. تحديد الحالة وموعد رمضان القادم
49
+ # شهر 9 = رمضان، شهر 10 = شوال (العيد)
50
+
51
+ if h_month == 9:
52
+ current_status = "ramadan"
53
+ target_date = None # لا يوجد عداد أثناء الشهر
54
+
55
+ elif h_month == 10 and h_day <= 3:
56
+ current_status = "eid" # عيد الفطر (أول 3 أيام من شوال)
57
+ target_date = None
58
+
59
+ else:
60
+ current_status = "counting"
61
+ # حساب موعد 1 رمضان القادم
62
+ # إذا كنا قبل رمضان في نفس السنة (شهر 1-8)
63
+ if h_month < 9:
64
+ target_h_year = h_year
65
+ else:
66
+ # إذا تجاوزنا رمضان (شهر 10-12)، نحسب للسنة القادمة
67
+ target_h_year = h_year + 1
68
+
69
+ # تحويل 1-9-YEAR إلى ميلادي
70
+ conv_req = requests.get(f"http://api.aladhan.com/v1/hToG?date=01-09-{target_h_year}")
71
+ g_data = conv_req.json()['data']['gregorian']
72
+
73
+ # إنشاء كائن datetime للموعد
74
+ target_str = g_data['date'] # Format: DD-MM-YYYY
75
+ target_date = datetime.strptime(target_str, "%d-%m-%Y")
76
+
77
+ last_api_update = time.time()
78
+ print(f"Updated State: {current_status} | Target: {target_date} | Hijri: {hijri_date_str}")
79
+
80
+ except Exception as e:
81
+ print(f"API Error: {e}")
82
+ # في حال الفشل نستخدم احتياطي يدوي (اختياري)
83
+ if not target_date:
84
+ target_date = datetime(2026, 2, 18) # تاريخ تقريبي للطوارئ
85
 
86
  @app.route('/time_data')
87
  def time_data():
88
+ update_timing_data() # تأكد من أن البيانات محدثة
89
+
90
+ data = {
91
+ "status": current_status,
92
+ "hijri": hijri_date_str,
93
+ "days": "00", "hours": "00", "minutes": "00", "seconds": "00"
94
+ }
95
+
96
+ if current_status == "counting" and target_date:
97
+ now = datetime.now()
98
+ diff = target_date - now
99
+ if diff.total_seconds() > 0:
100
+ days = diff.days
101
+ hours, rem = divmod(diff.seconds, 3600)
102
+ minutes, seconds = divmod(rem, 60)
103
+ data.update({
104
+ "days": f"{days:02}",
105
+ "hours": f"{hours:02}",
106
+ "minutes": f"{minutes:02}",
107
+ "seconds": f"{seconds:02}"
108
+ })
109
+
110
+ return jsonify(data)
111
 
112
  @app.route('/')
113
  def home():
114
+ # صفحة الويب مع النقطتين والصوت (محاكاة فقط في المتصفح)
115
+ return """
116
  <!DOCTYPE html>
117
  <html lang="ar" dir="rtl">
118
  <head>
119
  <meta charset="UTF-8">
120
+ <title>عداد رمضان الذكي</title>
121
  <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@700;900&display=swap" rel="stylesheet">
122
  <style>
123
+ body { background: #0f0f0f; color: white; font-family: 'Cairo'; overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; }
124
+ .bg { position: absolute; top:0; left:0; width:100%; height:100%; background: url('""" + BG_COUNTDOWN + """') center/cover; opacity: 0.4; z-index: -1; }
125
+ .title { font-size: 3vw; margin-bottom: 20px; text-shadow: 0 2px 10px black; }
126
+ .countdown { display: flex; align-items: center; gap: 10px; direction: ltr; }
127
+ .unit-group { text-align: center; }
128
+ .card { background: linear-gradient(180deg, #4CAF50, #2E7D32); width: 8vw; height: 10vw; border-radius: 10px; display: flex; justify-content: center; align-items: center; font-size: 5vw; font-weight: bold; box-shadow: 0 5px 15px rgba(0,0,0,0.5); border: 1px solid rgba(255,255,255,0.1); }
129
+ .colon { font-size: 5vw; font-weight: bold; color: #4CAF50; animation: blink 1s infinite; margin-top: -30px; }
130
+ .label { font-size: 1.2vw; color: #81C784; margin-top: 5px; }
131
+ .status-msg { font-size: 5vw; color: #FFD700; display: none; text-shadow: 0 0 20px rgba(255,215,0,0.5); }
132
+ @keyframes blink { 50% { opacity: 0; } }
 
 
 
 
 
 
 
 
 
 
 
133
  </style>
134
  </head>
135
  <body>
136
+ <div class="bg"></div>
137
+ <div id="hijri" style="position: absolute; top: 20px; right: 20px; font-size: 1.5vw; background: rgba(0,0,0,0.5); padding: 5px 15px; border-radius: 20px;">--/--/----</div>
138
+
139
+ <div id="counter-ui">
140
+ <div class="title">الوقت المتبقي على رمضان</div>
141
+ <div class="countdown">
142
+ <div class="unit-group"><div class="card" id="d">00</div><div class="label">أيام</div></div>
143
+ <div class="colon">:</div>
144
+ <div class="unit-group"><div class="card" id="h">00</div><div class="label">ساعات</div></div>
145
+ <div class="colon">:</div>
146
+ <div class="unit-group"><div class="card" id="m">00</div><div class="label">دقائق</div></div>
147
+ <div class="colon">:</div>
148
+ <div class="unit-group"><div class="card" id="s">00</div><div class="label">ثواني</div></div>
 
149
  </div>
150
  </div>
151
+
152
+ <div id="status-ui" class="status-msg"></div>
153
+
154
  <script>
155
  function update() {
156
+ fetch('/time_data').then(r => r.json()).then(d => {
157
+ document.getElementById('hijri').innerText = d.hijri;
158
+
159
+ if(d.status !== 'counting') {
160
+ document.getElementById('counter-ui').style.display = 'none';
161
+ let msg = document.getElementById('status-ui');
162
+ msg.style.display = 'block';
163
+ msg.innerText = (d.status === 'ramadan') ? 'رمضان مبارك' : 'عيد مبارك';
164
  } else {
165
+ document.getElementById('counter-ui').style.display = 'block';
166
+ document.getElementById('d').innerText = d.days;
167
+ document.getElementById('h').innerText = d.hours;
168
+ document.getElementById('m').innerText = d.minutes;
169
+ document.getElementById('s').innerText = d.seconds;
170
  }
171
  });
172
  }
 
176
  </body>
177
  </html>
178
  """
 
179
 
180
  def start_stream():
181
+ if not STREAM_KEY:
182
+ print("Error: STREAM_KEY is missing")
183
  return
184
 
185
  while True:
186
+ # تحديث الحالة قبل كل دورة بث
187
+ update_timing_data()
188
 
189
+ # إعداد متغيرات البث
190
+ target_ts = int(target_date.timestamp()) if target_date else 0
191
+
192
+ # 1. إعداد الصوت (صوت تكتكة الساعة)
193
+ # نستخدم aevalsrc لإنشاء نبضة صوتية كل ثانية (sin wave قصيرة)
194
+ audio_filter = "aevalsrc='sin(2*PI*t*1000)*exp(-10*mod(t,1))':s=44100"
 
 
195
 
196
+ # 2. إعداد الصورة والنصوص
197
+ if current_status == "ramadan":
198
+ bg_image = BG_RAMADAN
199
+ # لا حاجة للعداد، نعرض رسالة فقط
200
+ # بما أن FFmpeg لا يدعم العربية المعقدة بسهولة، نستخدم صورة جاهزة أو نص إنجليزي مزخرف كبديل آمن
201
+ # أو نحاول كتابة العربي المقطع ونأمل أن يدعمه السيرفر
202
+ vf_filter = (
203
+ f"scale=1280:720,setsar=1,"
204
+ f"drawtext=text='Ramadan Mubarak':x=(w-text_w)/2:y=(h-text_h)/2:fontsize=90:fontcolor=gold:shadowcolor=black:shadowx=5:shadowy=5"
205
+ )
206
+
207
+ elif current_status == "eid":
208
+ bg_image = BG_EID
209
+ vf_filter = (
210
  f"scale=1280:720,setsar=1,"
211
+ f"drawtext=text='Eid Mubarak':x=(w-text_w)/2:y=(h-text_h)/2:fontsize=90:fontcolor=#E040FB:shadowcolor=black:shadowx=5:shadowy=5"
212
+ )
213
+
214
+ else: # Counting
215
+ bg_image = BG_COUNTDOWN
216
+ # تنسيق العداد مع النقطتين
217
+ # نستخدم %{pts} لعرض الوقت المحلي ولكن FFmpeg لا يدعم العد التنازلي للتاريخ مباشرة بسهولة
218
+ # الحل: نستخدم صيغة خاصة لحساب الفرق أو نرسل النص جاهزاً (صعب في البث المستمر)
219
+ # الأفضل هنا: استخدام سكريبت بايثون لتوليد الصورة، لكن للتبسيط سنستخدم ميزة الـ drawtext المتطورة:
220
+ vf_filter = (
221
+ f"scale=1280:720,setsar=1,"
222
+ f"drawbox=y=ih/2-100:color=black@0.6:width=iw:height=200:t=fill,"
223
+ f"drawtext=text='{hijri_date_str}':x=50:y=50:fontsize=30:fontcolor=white:box=1:boxcolor=0x4CAF50@0.8,"
224
+ f"drawtext=text='Ramadan Countdown':x=(w-text_w)/2:y=200:fontsize=40:fontcolor=white,"
225
+ # العداد مع النقطتين (:). لاحظ المسافات والنقطتين بين الوحدات
226
+ f"drawtext=text=' %{{pts\\:localtime\\:{target_ts}\\:%d}} : %{{pts\\:localtime\\:{target_ts}\\:%H}} : %{{pts\\:localtime\\:{target_ts}\\:%M}} : %{{pts\\:localtime\\:{target_ts}\\:%S}} ':"
227
+ f"x=(w-text_w)/2:y=(h-text_h)/2+20:fontsize=80:fontcolor=white:box=1:boxcolor=0x4CAF50@0.9:boxborderw=20"
228
+ )
229
+
230
+ # أمر FFmpeg
231
+ ffmpeg_cmd = [
232
+ 'ffmpeg', '-re',
233
+ '-loop', '1', '-i', bg_image, # مدخل الفيديو (الصورة)
234
+ '-f', 'lavfi', '-i', audio_filter, # مدخل الصوت (التكتكة)
235
+ '-vf', vf_filter, # فلاتر الفيديو (النصوص)
236
+ '-c:v', 'libx264', '-preset', 'veryfast', '-b:v', '3000k',
237
+ '-c:a', 'aac', '-b:a', '128k', # ترميز الصوت
238
+ '-g', '60', '-f', 'flv',
239
+ f"{STREAM_URL}{STREAM_KEY}"
240
  ]
241
+
242
  try:
243
+ print(f"Starting Stream Mode: {current_status}")
244
  subprocess.run(ffmpeg_cmd, check=True)
245
  except Exception as e:
246
+ print(f"Stream interrupted: {e}")
247
  time.sleep(5)
248
 
249
  if __name__ == "__main__":
 
250
  threading.Thread(target=lambda: app.run(host='0.0.0.0', port=7860, debug=False, use_reloader=False), daemon=True).start()
 
251
  start_stream()