Update app.py
Browse files
app.py
CHANGED
|
@@ -31,7 +31,7 @@ def log(msg):
|
|
| 31 |
f.write(line + "\n")
|
| 32 |
|
| 33 |
# ------------------------------------------------------------
|
| 34 |
-
# حفظ الكوكيز
|
| 35 |
# ------------------------------------------------------------
|
| 36 |
def save_cookies():
|
| 37 |
if TIKTOK_COOKIES:
|
|
@@ -41,7 +41,21 @@ def save_cookies():
|
|
| 41 |
with open("/tmp/tiktok_cookies_adult.txt", "w") as f:
|
| 42 |
f.write(TIKTOK_COOKIES_ADULT)
|
| 43 |
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
# ------------------------------------------------------------
|
| 47 |
# أدوات مساعدة
|
|
@@ -106,20 +120,14 @@ def start_stream(stream_key, stream_url):
|
|
| 106 |
"-hide_banner", "-loglevel", "warning",
|
| 107 |
"-re",
|
| 108 |
"-thread_queue_size", "2048",
|
| 109 |
-
"-fflags", "+genpts+igndts",
|
| 110 |
"-i", stream_url,
|
| 111 |
-
|
| 112 |
-
# فيديو: نسخ مباشر
|
| 113 |
"-c:v", "copy",
|
| 114 |
-
|
| 115 |
-
# صوت: ترميز AAC خفيف مع تصحيح التزامن فقط
|
| 116 |
"-c:a", "aac",
|
| 117 |
"-b:a", "192k",
|
| 118 |
"-ar", "44100",
|
| 119 |
"-af", "aresample=async=1:first_pts=0",
|
| 120 |
"-async", "1",
|
| 121 |
-
|
| 122 |
-
# إعادة اتصال محسنة (مستقرة)
|
| 123 |
"-reconnect", "1",
|
| 124 |
"-reconnect_streamed", "1",
|
| 125 |
"-reconnect_at_eof", "1",
|
|
@@ -140,7 +148,6 @@ def start_stream(stream_key, stream_url):
|
|
| 140 |
# ------------------------------------------------------------
|
| 141 |
def build_youtube_client():
|
| 142 |
try:
|
| 143 |
-
# محاولة تحميل توكن موجود
|
| 144 |
if os.path.exists(TOKEN_FILE):
|
| 145 |
with open(TOKEN_FILE, "rb") as f:
|
| 146 |
creds = pickle.load(f)
|
|
@@ -152,7 +159,6 @@ def build_youtube_client():
|
|
| 152 |
pickle.dump(creds, f)
|
| 153 |
return build('youtube', 'v3', credentials=creds)
|
| 154 |
|
| 155 |
-
# إنشاء جديد من المتغير البيئي
|
| 156 |
creds_json = os.getenv("YT_CREDENTIALS_JSON")
|
| 157 |
if not creds_json:
|
| 158 |
return None
|
|
@@ -164,7 +170,7 @@ def build_youtube_client():
|
|
| 164 |
token_uri=data.get("token_uri"),
|
| 165 |
client_id=data.get("client_id"),
|
| 166 |
client_secret=data.get("client_secret"),
|
| 167 |
-
scopes=data.get("scopes", ["https://www.googleapis.com/auth/youtube.force-ssl"])
|
| 168 |
)
|
| 169 |
if creds.expired and creds.refresh_token:
|
| 170 |
creds.refresh(Request())
|
|
@@ -175,6 +181,22 @@ def build_youtube_client():
|
|
| 175 |
log(f"❌ فشل بناء عميل YouTube: {e}")
|
| 176 |
return None
|
| 177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
def create_live_stream(yt):
|
| 179 |
try:
|
| 180 |
stream_insert = yt.liveStreams().insert(
|
|
@@ -207,7 +229,6 @@ def bind_stream_to_broadcast(yt, broadcast_id, stream_id):
|
|
| 207 |
return False
|
| 208 |
|
| 209 |
def finalize_all_broadcasts():
|
| 210 |
-
"""إنهاء جميع البثوث النشطة لبداية نظيفة"""
|
| 211 |
try:
|
| 212 |
yt = build_youtube_client()
|
| 213 |
if not yt:
|
|
@@ -226,7 +247,6 @@ def finalize_all_broadcasts():
|
|
| 226 |
log(f"❌ خطأ في التنظيف: {e}")
|
| 227 |
|
| 228 |
def create_new_broadcast():
|
| 229 |
-
"""إنشاء بث جديد كامل (API) وإرجاع المفتاح والمعرف"""
|
| 230 |
try:
|
| 231 |
yt = build_youtube_client()
|
| 232 |
if not yt:
|
|
@@ -342,7 +362,6 @@ def monitor_loop():
|
|
| 342 |
|
| 343 |
stream_key = None
|
| 344 |
bid = None
|
| 345 |
-
# المحاولة الأولى: YouTube API
|
| 346 |
stream_key, bid = create_new_broadcast()
|
| 347 |
if not stream_key:
|
| 348 |
log("⚠️ فشل API، استخدام المفتاح الاحتياطي...")
|
|
@@ -392,7 +411,30 @@ def monitor_loop():
|
|
| 392 |
time.sleep(30)
|
| 393 |
|
| 394 |
if __name__ == "__main__":
|
| 395 |
-
log("✅ بدء تشغيل المحرك النهائي
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 396 |
t = threading.Thread(target=monitor_loop, daemon=True)
|
| 397 |
t.start()
|
| 398 |
while True:
|
|
|
|
| 31 |
f.write(line + "\n")
|
| 32 |
|
| 33 |
# ------------------------------------------------------------
|
| 34 |
+
# حفظ وفحص الكوكيز
|
| 35 |
# ------------------------------------------------------------
|
| 36 |
def save_cookies():
|
| 37 |
if TIKTOK_COOKIES:
|
|
|
|
| 41 |
with open("/tmp/tiktok_cookies_adult.txt", "w") as f:
|
| 42 |
f.write(TIKTOK_COOKIES_ADULT)
|
| 43 |
|
| 44 |
+
def check_cookies_validity(file_path):
|
| 45 |
+
"""التحقق من أن الكوكيز بصيغة صحيحة وتحتوي على جلسة نشطة"""
|
| 46 |
+
if not os.path.exists(file_path):
|
| 47 |
+
return False
|
| 48 |
+
try:
|
| 49 |
+
with open(file_path, "r", encoding="utf-8") as f:
|
| 50 |
+
content = f.read()
|
| 51 |
+
# فحص هل الملف يحتوي على التوكن الأساسي لتيك توك
|
| 52 |
+
if "sessionid" in content or "tt_chain_token" in content:
|
| 53 |
+
return True
|
| 54 |
+
else:
|
| 55 |
+
return False
|
| 56 |
+
except Exception as e:
|
| 57 |
+
log(f"❌ خطأ أثناء فحص الكوكيز: {e}")
|
| 58 |
+
return False
|
| 59 |
|
| 60 |
# ------------------------------------------------------------
|
| 61 |
# أدوات مساعدة
|
|
|
|
| 120 |
"-hide_banner", "-loglevel", "warning",
|
| 121 |
"-re",
|
| 122 |
"-thread_queue_size", "2048",
|
| 123 |
+
"-fflags", "+genpts+igndts",
|
| 124 |
"-i", stream_url,
|
|
|
|
|
|
|
| 125 |
"-c:v", "copy",
|
|
|
|
|
|
|
| 126 |
"-c:a", "aac",
|
| 127 |
"-b:a", "192k",
|
| 128 |
"-ar", "44100",
|
| 129 |
"-af", "aresample=async=1:first_pts=0",
|
| 130 |
"-async", "1",
|
|
|
|
|
|
|
| 131 |
"-reconnect", "1",
|
| 132 |
"-reconnect_streamed", "1",
|
| 133 |
"-reconnect_at_eof", "1",
|
|
|
|
| 148 |
# ------------------------------------------------------------
|
| 149 |
def build_youtube_client():
|
| 150 |
try:
|
|
|
|
| 151 |
if os.path.exists(TOKEN_FILE):
|
| 152 |
with open(TOKEN_FILE, "rb") as f:
|
| 153 |
creds = pickle.load(f)
|
|
|
|
| 159 |
pickle.dump(creds, f)
|
| 160 |
return build('youtube', 'v3', credentials=creds)
|
| 161 |
|
|
|
|
| 162 |
creds_json = os.getenv("YT_CREDENTIALS_JSON")
|
| 163 |
if not creds_json:
|
| 164 |
return None
|
|
|
|
| 170 |
token_uri=data.get("token_uri"),
|
| 171 |
client_id=data.get("client_id"),
|
| 172 |
client_secret=data.get("client_secret"),
|
| 173 |
+
scopes=data.get("scopes", ["https://www.googleapis.com/auth/youtube.force-ssl", "https://www.googleapis.com/auth/youtube.readonly"])
|
| 174 |
)
|
| 175 |
if creds.expired and creds.refresh_token:
|
| 176 |
creds.refresh(Request())
|
|
|
|
| 181 |
log(f"❌ فشل بناء عميل YouTube: {e}")
|
| 182 |
return None
|
| 183 |
|
| 184 |
+
def log_youtube_channel_name(yt):
|
| 185 |
+
"""جلب اسم قناة اليوتيوب المرتبطة بالتوكن وطباعتها"""
|
| 186 |
+
try:
|
| 187 |
+
request = yt.channels().list(part="snippet", mine=True)
|
| 188 |
+
response = request.execute()
|
| 189 |
+
if "items" in response and len(response["items"]) > 0:
|
| 190 |
+
channel_name = response["items"][0]["snippet"]["title"]
|
| 191 |
+
log(f"📺 تم بنجاح الاتصال بقناة اليوتيوب: 【 {channel_name} 】")
|
| 192 |
+
return channel_name
|
| 193 |
+
else:
|
| 194 |
+
log("⚠️ التوكن يعمل ولكن لم يتم العثور على قناة يوتيوب مرتبطة به!")
|
| 195 |
+
return None
|
| 196 |
+
except Exception as e:
|
| 197 |
+
log(f"❌ فشل جلب اسم القناة: {e}")
|
| 198 |
+
return None
|
| 199 |
+
|
| 200 |
def create_live_stream(yt):
|
| 201 |
try:
|
| 202 |
stream_insert = yt.liveStreams().insert(
|
|
|
|
| 229 |
return False
|
| 230 |
|
| 231 |
def finalize_all_broadcasts():
|
|
|
|
| 232 |
try:
|
| 233 |
yt = build_youtube_client()
|
| 234 |
if not yt:
|
|
|
|
| 247 |
log(f"❌ خطأ في التنظيف: {e}")
|
| 248 |
|
| 249 |
def create_new_broadcast():
|
|
|
|
| 250 |
try:
|
| 251 |
yt = build_youtube_client()
|
| 252 |
if not yt:
|
|
|
|
| 362 |
|
| 363 |
stream_key = None
|
| 364 |
bid = None
|
|
|
|
| 365 |
stream_key, bid = create_new_broadcast()
|
| 366 |
if not stream_key:
|
| 367 |
log("⚠️ فشل API، استخدام المفتاح الاحتياطي...")
|
|
|
|
| 411 |
time.sleep(30)
|
| 412 |
|
| 413 |
if __name__ == "__main__":
|
| 414 |
+
log("✅ بدء تشغيل المحرك النهائي...")
|
| 415 |
+
|
| 416 |
+
# حفظ الكوكيز وإجراء فحص مبدئي لها
|
| 417 |
+
save_cookies()
|
| 418 |
+
if os.path.exists("/tmp/tiktok_cookies.txt"):
|
| 419 |
+
if check_cookies_validity("/tmp/tiktok_cookies.txt"):
|
| 420 |
+
log("🎯 فحص الكوكيز: كوكيز الحساب العادي تبدو صالحة (تحتوي على جلسة).")
|
| 421 |
+
else:
|
| 422 |
+
log("🚨 فحص الكوكيز: كوكيز الحساب العادي تالفة أو فارغة!")
|
| 423 |
+
|
| 424 |
+
if os.path.exists("/tmp/tiktok_cookies_adult.txt"):
|
| 425 |
+
if check_cookies_validity("/tmp/tiktok_cookies_adult.txt"):
|
| 426 |
+
log("🎯 فحص الكوكيز: كوكيز حساب البالغين (+18) تبدو صالحة.")
|
| 427 |
+
else:
|
| 428 |
+
log("🚨 فحص الكوكيز: كوكيز حساب البالغين تالفة أو فارغة!")
|
| 429 |
+
|
| 430 |
+
# فحص اليوتيوب ومعرفة اسم القناة
|
| 431 |
+
log("🔍 جاري الاتصال بخوادم اليوتيوب...")
|
| 432 |
+
yt_client = build_youtube_client()
|
| 433 |
+
if yt_client:
|
| 434 |
+
log_youtube_channel_name(yt_client)
|
| 435 |
+
else:
|
| 436 |
+
log("❌ لم يتم العثور على توكن يوتيوب صحيح أو حدث خطأ في الاتصال.")
|
| 437 |
+
|
| 438 |
t = threading.Thread(target=monitor_loop, daemon=True)
|
| 439 |
t.start()
|
| 440 |
while True:
|