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

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +129 -188
main.py CHANGED
@@ -3,170 +3,139 @@ import time
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,76 +145,48 @@ def home():
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()
 
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():
60
+ html_content = """
 
61
  <!DOCTYPE html>
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; }
69
+ .video-player {
70
+ position: relative; width: 100vw; height: 100vh;
71
+ background: url('""" + BG_IMAGE + """') no-repeat center center;
72
+ background-size: cover; display: flex; flex-direction: column; justify-content: center; align-items: center;
73
+ }
74
+ .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }
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;
82
+ font-size: 70px; font-weight: 900; display: flex;
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>
94
  </head>
95
  <body>
96
+ <div class="video-player">
97
+ <div class="overlay"></div>
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>
128
  function update() {
129
+ fetch('/time_data').then(res => res.json()).then(data => {
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;
138
+ document.getElementById('seconds').innerText = data.seconds;
 
139
  }
140
  });
141
  }
 
145
  </body>
146
  </html>
147
  """
148
+ return html_content
149
 
150
  def start_stream():
151
+ if not STREAM_KEY:
152
+ print("Error: STREAM_KEY not found.")
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__":
189
+ # تشغيل سيرفر الويب في خلفية مستقلة
190
  threading.Thread(target=lambda: app.run(host='0.0.0.0', port=7860, debug=False, use_reloader=False), daemon=True).start()
191
+ # بدء البث المباشر
192
  start_stream()