Mroo9 commited on
Commit
90256d0
·
verified ·
1 Parent(s): c01ef64

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -54
app.py CHANGED
@@ -5,7 +5,7 @@ import threading
5
  import json
6
  import pickle
7
  import psutil
8
- from datetime import datetime, timezone, timedelta
9
  from google.oauth2.credentials import Credentials
10
  from google.auth.transport.requests import Request
11
  from googleapiclient.discovery import build
@@ -60,7 +60,7 @@ def kill_process_tree(pid):
60
  def get_tiktok_stream_url():
61
  try:
62
  url = f"https://www.tiktok.com/{TIKTOK_USERNAME}/live"
63
- cmd = ["streamlink", "--stream-url", url, "best,720p,480p", "--retry-streams", "5", "--retry-open", "3"]
64
  if os.path.exists("/tmp/tiktok_cookies_adult.txt"):
65
  cmd.extend(["--cookies", "/tmp/tiktok_cookies_adult.txt"])
66
  elif os.path.exists("/tmp/tiktok_cookies.txt"):
@@ -84,28 +84,30 @@ def get_tiktok_stream_url():
84
 
85
  def start_stream(stream_key, stream_url):
86
  if not stream_key or not stream_url: return None
87
- log("🎬 بدء البث (الأبعاد الطولية الحقيقية لمنع الاقتصاص)...")
88
  rtmp_url = f"rtmp://a.rtmp.youtube.com/live2/{stream_key}"
89
-
 
90
  cmd = [
91
  "nice", "-n", "19", "ffmpeg", "-hide_banner", "-loglevel", "warning",
92
  "-thread_queue_size", "2048",
93
  "-user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
94
  "-headers", "Referer: https://www.tiktok.com/\r\n",
95
-
96
- "-rw_timeout", "15000000",
97
- "-fflags", "+genpts+discardcorrupt", "-flags", "+global_header", "-i", stream_url,
98
-
99
- "-c:v", "libx264", "-preset", "ultrafast", "-b:v", "2500k", "-maxrate", "2500k", "-bufsize", "5000k",
100
- "-pix_fmt", "yuv420p", "-g", "60", "-r", "30", "-fps_mode", "cfr",
101
-
102
- # التعديل البرمجي هنا: تغيير الأبعاد إلى الطولية 1080x1920 وملاءمتها بالكامل لحماية الصورة من القص
103
- "-vf", "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1",
104
-
105
- "-c:a", "aac", "-b:a", "192k", "-ar", "44100", "-profile:a", "aac_low",
106
- "-af", "aresample=async=1:first_pts=0",
107
-
108
- "-rtmp_live", "live", "-max_muxing_queue_size", "2048", "-f", "flv", rtmp_url
 
109
  ]
110
  with open(FFMPEG_LOG, "w") as stderr_file:
111
  proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=stderr_file, preexec_fn=os.setsid)
@@ -140,17 +142,15 @@ def create_new_broadcast():
140
  yt = build_youtube_client()
141
  if not yt: return None, None
142
 
143
- baghdad_tz = timezone(timedelta(hours=3))
144
- now = datetime.now(baghdad_tz)
145
  date_str = now.strftime('%d-%m-%Y %H:%M')
146
-
147
  title = f"🔥 بث تيك توك أعدام المباشر | {date_str} 🚀"
148
  description = (
149
- "أهلاً بكم في البث المباشر المخصص لـ دكتور أعدام.\n"
150
  "استمتعوا معنا بأجواء البث وتفاعلوا في التعليقات!\n\n"
151
  "🔔 لا تنسوا الاشتراك في القناة وتفعيل زر التنبيهات ليصلكم كل جديد فور انطلاق البث.\n"
152
  "شكراً لدعمكم المتواصل!\n\n"
153
- "#دكتور_إعدام #بث_مباشر #تيك_توك #TikTokLive #الاردن #بث #مباشر #a3dam_111"
154
  )
155
 
156
  insert_body = {
@@ -167,7 +167,6 @@ def create_new_broadcast():
167
  bid = new_broadcast["id"]
168
  log(f"✅ بث جديد: {bid} | {title}")
169
 
170
- # ملاحظة: يوتيوب يتعرف تلقائياً على البث الطولي بناءً على أبعاد دفق الـ ffmpeg المرسل (1080x1920)
171
  stream_insert = yt.liveStreams().insert(
172
  part="snippet,cdn,contentDetails",
173
  body={"snippet": {"title": "TikTok Stream Key"}, "cdn": {"ingestionType": "rtmp", "resolution": "1080p", "frameRate": "30fps"}, "contentDetails": {"isReusable": True}}
@@ -184,41 +183,62 @@ def create_new_broadcast():
184
  log(f"❌ فشل إنشاء بث جديد: {e}")
185
  return None, None
186
 
187
- def finalize_all_broadcasts():
 
 
 
 
188
  try:
 
 
 
 
 
189
  yt = build_youtube_client()
190
- if not yt: return
191
- broadcasts = yt.liveBroadcasts().list(mine=True, part="id,status").execute()
192
- for item in broadcasts.get("items", []):
193
- bid = item["id"]
194
- status = item.get("status", {}).get("lifeCycleStatus", "")
195
- if status in ["ready", "created", "live", "testing"]:
196
- try:
197
- yt.liveBroadcasts().transition(broadcastStatus="complete", id=bid, part="status").execute()
198
- except: pass
199
- except: pass
 
 
 
 
 
 
 
 
200
 
201
  def finalize_current_broadcast(broadcast_id):
202
  if not broadcast_id: return
203
- log(f"⚠️ جاري إغلاق البث على يوتيوب رسمياً... ID: {broadcast_id}")
204
  try:
205
  yt = build_youtube_client()
206
  if not yt: return
207
  yt.liveBroadcasts().transition(broadcastStatus="complete", id=broadcast_id, part="status").execute()
208
- log("✅ تم إغلاق البث في يوتيوب بنجاح.")
209
- except Exception as e:
210
- log(f"❌ خطأ أثناء إغلاق البث: {e}")
211
- pass
212
- if os.path.exists(BROADCAST_FILE): os.remove(BROADCAST_FILE)
213
 
214
  # ------------------------------------------------------------
215
  # المحرك الرئيسي
216
  # ------------------------------------------------------------
217
  def monitor_loop():
 
 
218
  time.sleep(2)
219
  if os.path.exists(LOCK_FILE): return
220
  with open(LOCK_FILE, "w") as f: f.write(str(os.getpid()))
221
- finalize_all_broadcasts()
 
 
 
222
  ffmpeg_proc = None
223
  was_streaming = False
224
  consecutive_fails = 0
@@ -229,19 +249,18 @@ def monitor_loop():
229
  try:
230
  stream_url = get_tiktok_stream_url()
231
  if stream_url:
232
- if consecutive_fails > 0:
233
- log("✅ تم التقاط رابط التيك توك مجدداً بعد الانقطاع.")
234
  consecutive_fails = 0
235
-
236
- if was_streaming and ffmpeg_proc and ffmpeg_proc.poll() is None: pass
237
  elif was_streaming and ffmpeg_proc and ffmpeg_proc.poll() is not None:
238
  kill_process_tree(ffmpeg_proc.pid)
239
  ffmpeg_proc = start_stream(current_stream_key, stream_url)
240
  else:
241
  if not current_broadcast_id:
242
- finalize_all_broadcasts()
243
  stream_key, bid = create_new_broadcast()
244
- if not stream_key: stream_key = CUSTOM_STREAM_KEY
 
245
  current_broadcast_id = bid
246
  current_stream_key = stream_key
247
  ffmpeg_proc = start_stream(current_stream_key, stream_url)
@@ -249,20 +268,17 @@ def monitor_loop():
249
  else:
250
  if was_streaming:
251
  consecutive_fails += 1
252
- log(f"⚠️ تعذر جلب رابط التيك توك. محاولة رقم {consecutive_fails}/20")
253
-
254
- # تم زيادة مدة الانتظار إلى 20 محاولة (حوالي 10 دقائق)
255
- if consecutive_fails >= 20:
256
- log("❌ انقضى وقت الانتظار (10 دقائق) والمذيع لم يعد أو الرابط انقطع نهائياً. سيتم إنهاء البث.")
257
  if ffmpeg_proc: kill_process_tree(ffmpeg_proc.pid)
258
  ffmpeg_proc = None
259
  was_streaming = False
260
  if current_broadcast_id:
261
  finalize_current_broadcast(current_broadcast_id)
262
  current_broadcast_id = None
 
263
  time.sleep(30)
264
  except Exception as e:
265
- log(f"❌ خطأ غير متوقع في اللوب: {e}")
266
  time.sleep(30)
267
 
268
  app = Flask(__name__)
 
5
  import json
6
  import pickle
7
  import psutil
8
+ from datetime import datetime, timezone
9
  from google.oauth2.credentials import Credentials
10
  from google.auth.transport.requests import Request
11
  from googleapiclient.discovery import build
 
60
  def get_tiktok_stream_url():
61
  try:
62
  url = f"https://www.tiktok.com/{TIKTOK_USERNAME}/live"
63
+ cmd = ["streamlink", "--stream-url", url, "best", "--retry-streams", "5", "--retry-open", "3"]
64
  if os.path.exists("/tmp/tiktok_cookies_adult.txt"):
65
  cmd.extend(["--cookies", "/tmp/tiktok_cookies_adult.txt"])
66
  elif os.path.exists("/tmp/tiktok_cookies.txt"):
 
84
 
85
  def start_stream(stream_key, stream_url):
86
  if not stream_key or not stream_url: return None
87
+ log("🎬 بدء البث (تحويل الفيديو H.264 + فلاتر صوتية + تخطي الحظر)...")
88
  rtmp_url = f"rtmp://a.rtmp.youtube.com/live2/{stream_key}"
89
+ try: subprocess.run(["killall", "-9", "ffmpeg", "yt-dlp", "streamlink"], stderr=subprocess.DEVNULL)
90
+ except: pass
91
  cmd = [
92
  "nice", "-n", "19", "ffmpeg", "-hide_banner", "-loglevel", "warning",
93
  "-thread_queue_size", "2048",
94
  "-user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
95
  "-headers", "Referer: https://www.tiktok.com/\r\n",
96
+ "-fflags", "+genpts+discardcorrupt+igndts", # إصلاح التزامن
97
+ "-flags", "+global_header",
98
+ "-reconnect", "1",
99
+ "-reconnect_at_eof", "1",
100
+ "-reconnect_delay_max", "60",
101
+ "-i", stream_url,
102
+ "-c:v", "libx264", "-preset", "ultrafast", "-b:v", "2500k",
103
+ "-maxrate", "2500k", "-bufsize", "5000k",
104
+ "-pix_fmt", "yuv420p",
105
+ "-g", "60",
106
+ "-c:a", "aac", "-b:a", "192k", "-ar", "44100",
107
+ "-profile:a", "aac_low",
108
+ "-af", "aresample=async=1000:min_hard_comp=0.100000:first_pts=0,highpass=f=50,lowpass=f=15000,dynaudnorm=f=150:g=15:m=25:p=0.95",
109
+ "-max_muxing_queue_size", "2048",
110
+ "-f", "flv", rtmp_url
111
  ]
112
  with open(FFMPEG_LOG, "w") as stderr_file:
113
  proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=stderr_file, preexec_fn=os.setsid)
 
142
  yt = build_youtube_client()
143
  if not yt: return None, None
144
 
145
+ now = datetime.now(timezone.utc)
 
146
  date_str = now.strftime('%d-%m-%Y %H:%M')
 
147
  title = f"🔥 بث تيك توك أعدام المباشر | {date_str} 🚀"
148
  description = (
149
+ "أهلاً بكم في البث المباشر المخصص لـ أعدام.\n"
150
  "استمتعوا معنا بأجواء البث وتفاعلوا في التعليقات!\n\n"
151
  "🔔 لا تنسوا الاشتراك في القناة وتفعيل زر التنبيهات ليصلكم كل جديد فور انطلاق البث.\n"
152
  "شكراً لدعمكم المتواصل!\n\n"
153
+ "#أعدام #بث_مباشر #تيك_توك #TikTokLive #الاردن #بث #مباشر #a3dam_111"
154
  )
155
 
156
  insert_body = {
 
167
  bid = new_broadcast["id"]
168
  log(f"✅ بث جديد: {bid} | {title}")
169
 
 
170
  stream_insert = yt.liveStreams().insert(
171
  part="snippet,cdn,contentDetails",
172
  body={"snippet": {"title": "TikTok Stream Key"}, "cdn": {"ingestionType": "rtmp", "resolution": "1080p", "frameRate": "30fps"}, "contentDetails": {"isReusable": True}}
 
183
  log(f"❌ فشل إنشاء بث جديد: {e}")
184
  return None, None
185
 
186
+ # ✅ دالة جديدة: تنظيف البث السابق لنفس المساحة فقط
187
+ def cleanup_own_previous_broadcast():
188
+ """تنهي بثاً سابقاً لهذه المساحة فقط (إن وُجد وما زال مفتوحاً)"""
189
+ if not os.path.exists(BROADCAST_FILE):
190
+ return
191
  try:
192
+ with open(BROADCAST_FILE, "r") as f:
193
+ data = json.load(f)
194
+ bid = data.get("broadcast_id")
195
+ if not bid:
196
+ return
197
  yt = build_youtube_client()
198
+ if not yt:
199
+ return
200
+ # جلب حالة البث
201
+ resp = yt.liveBroadcasts().list(id=bid, part="status").execute()
202
+ items = resp.get("items", [])
203
+ if not items:
204
+ os.remove(BROADCAST_FILE)
205
+ return
206
+ status = items[0]["status"]["lifeCycleStatus"]
207
+ if status in ["live", "ready", "created", "testing"]:
208
+ log(f"🧹 إنهاء بث سابق لهذه المساحة: {bid}")
209
+ yt.liveBroadcasts().transition(broadcastStatus="complete", id=bid, part="status").execute()
210
+ # نحذف الملف على أية حال لأننا سننشئ بثاً جديداً
211
+ os.remove(BROADCAST_FILE)
212
+ except Exception as e:
213
+ log(f"⚠️ تعذر تنظيف البث السابق: {e}")
214
+ if os.path.exists(BROADCAST_FILE):
215
+ os.remove(BROADCAST_FILE)
216
 
217
  def finalize_current_broadcast(broadcast_id):
218
  if not broadcast_id: return
 
219
  try:
220
  yt = build_youtube_client()
221
  if not yt: return
222
  yt.liveBroadcasts().transition(broadcastStatus="complete", id=broadcast_id, part="status").execute()
223
+ log(f"🛑 تم إنهاء البث: {broadcast_id}")
224
+ except Exception as e:
225
+ log(f"⚠️ فشل إنهاء البث: {e}")
226
+ if os.path.exists(BROADCAST_FILE):
227
+ os.remove(BROADCAST_FILE)
228
 
229
  # ------------------------------------------------------------
230
  # المحرك الرئيسي
231
  # ------------------------------------------------------------
232
  def monitor_loop():
233
+ try: subprocess.run(["killall", "-9", "ffmpeg", "yt-dlp", "streamlink"], stderr=subprocess.DEVNULL)
234
+ except: pass
235
  time.sleep(2)
236
  if os.path.exists(LOCK_FILE): return
237
  with open(LOCK_FILE, "w") as f: f.write(str(os.getpid()))
238
+
239
+ # ✅ تنظيف بث هذه المساحة فقط (وليس كل البثوث)
240
+ cleanup_own_previous_broadcast()
241
+
242
  ffmpeg_proc = None
243
  was_streaming = False
244
  consecutive_fails = 0
 
249
  try:
250
  stream_url = get_tiktok_stream_url()
251
  if stream_url:
 
 
252
  consecutive_fails = 0
253
+ if was_streaming and ffmpeg_proc and ffmpeg_proc.poll() is None:
254
+ pass
255
  elif was_streaming and ffmpeg_proc and ffmpeg_proc.poll() is not None:
256
  kill_process_tree(ffmpeg_proc.pid)
257
  ffmpeg_proc = start_stream(current_stream_key, stream_url)
258
  else:
259
  if not current_broadcast_id:
260
+ # لا ننهي كل البثوث، فقط ننشئ بثًا جديدًا (المساحة الأخرى مستقلة)
261
  stream_key, bid = create_new_broadcast()
262
+ if not stream_key:
263
+ stream_key = CUSTOM_STREAM_KEY
264
  current_broadcast_id = bid
265
  current_stream_key = stream_key
266
  ffmpeg_proc = start_stream(current_stream_key, stream_url)
 
268
  else:
269
  if was_streaming:
270
  consecutive_fails += 1
271
+ if consecutive_fails >= 6:
 
 
 
 
272
  if ffmpeg_proc: kill_process_tree(ffmpeg_proc.pid)
273
  ffmpeg_proc = None
274
  was_streaming = False
275
  if current_broadcast_id:
276
  finalize_current_broadcast(current_broadcast_id)
277
  current_broadcast_id = None
278
+ current_stream_key = None
279
  time.sleep(30)
280
  except Exception as e:
281
+ log(f"❌ خطأ في حلقة المراقبة: {e}")
282
  time.sleep(30)
283
 
284
  app = Flask(__name__)