Reooiq commited on
Commit
896c7d3
·
verified ·
1 Parent(s): 1b9f986

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +310 -215
index.js CHANGED
@@ -12,6 +12,7 @@ const MY_PROXY_URL = "https://tg-proxy.dr-toktok00.workers.dev";
12
 
13
  dns.setServers(['8.8.8.8']);
14
 
 
15
  const COUNTRY_FLAGS = {
16
  'SA': { name: 'السعودية', flag: '🇸🇦' },
17
  'EG': { name: 'مصر', flag: '🇪🇬' },
@@ -81,143 +82,148 @@ const COUNTRY_FLAGS = {
81
  'IE': { name: 'أيرلندا', flag: '🇮🇪' },
82
  };
83
 
84
- // ✅ قاموس الهدايا - القيم بالدiamonds
85
- const GIFT_DIAMONDS = {
86
- 5953: 25, 1817: 1, 1816: 1, 1815: 1, 1814: 1, 1813: 1, 1812: 1, 1811: 1,
87
- 1810: 5, 1809: 5, 1808: 5, 1807: 5, 1806: 10, 1805: 10, 1804: 10,
88
- 1803: 15, 1802: 20, 1801: 25, 1800: 30, 1799: 35, 1798: 40, 1797: 50,
89
- 1796: 60, 1795: 70, 1794: 80, 1793: 90, 1792: 100, 1791: 150, 1790: 200,
90
- 1789: 250, 1788: 300, 1787: 400, 1786: 500, 1785: 700, 1784: 1000,
91
- 1783: 1500, 1782: 2000, 1781: 3000, 1780: 5000, 1779: 7000, 1778: 10000,
92
- 1777: 15000, 1776: 20000, 1775: 30000, 1774: 50000, 1773: 75000, 1772: 100000,
93
- 5952: 1, 5951: 5, 5950: 10, 5949: 15, 5948: 20, 5947: 30, 5946: 50,
94
- 5945: 100, 5944: 200, 5943: 500, 5942: 1000, 5941: 2000, 5940: 5000,
95
- 5939: 10000, 5938: 25000, 5937: 50000, 5936: 100000,
96
- 5935: 1, 5934: 3, 5933: 5, 5932: 10, 5931: 15, 5930: 20,
97
- 5929: 30, 5928: 40, 5927: 50, 5926: 60, 5925: 80, 5924: 100,
98
- 5923: 150, 5922: 200, 5921: 300, 5920: 400, 5919: 500, 5918: 700,
99
- 5917: 1000, 5916: 1500, 5915: 2000, 5914: 3000, 5913: 5000, 5912: 10000,
100
- 5911: 20000, 5910: 50000, 5909: 100000, 5908: 250000, 5907: 500000,
101
- 5906: 1000000, 5905: 10, 5904: 25, 5903: 50, 5902: 100,
102
- 5901: 200, 5900: 500, 5899: 1000, 5898: 2000, 5897: 5000,
103
- 5896: 10000, 5895: 20000, 5894: 50000, 5893: 100000,
104
- 5892: 250000, 5891: 500000, 5890: 1000000,
105
- 5729: 1, 5728: 5, 5727: 10, 5726: 15, 5725: 20, 5724: 30,
106
- 5723: 50, 5722: 100, 5721: 200, 5720: 500, 5719: 1000,
107
- 5718: 2000, 5717: 5000, 5716: 10000, 5715: 25000, 5714: 50000,
108
- 5713: 100000, 5712: 250000, 5711: 500000, 5710: 1000000,
109
- 5972: 1, 5971: 1, 5970: 1, 5969: 1, 5968: 3, 5967: 5,
110
- 5966: 10, 5965: 15, 5964: 20, 5963: 30, 5962: 40, 5961: 50,
111
- 5960: 100,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  };
113
 
114
- // ✅ قاموس الأسماء بالعربي
115
- const GIFT_ARABIC = {
116
- 'rose': 'وردة', 'rosebud': 'برعم ورد', 'smile': 'ابتسامة', 'heart': 'قلب',
117
- 'thumbs up': 'إبهام', 'thumbsup': 'إبهام', 'star': 'نجمة',
118
- 'fire': 'نار', 'flame': 'لهب', 'crown': 'تاج', 'diamond': 'ماسة',
119
- 'tiger': 'نمر', 'dragon': 'تنين', 'unicorn': 'أحادي القرن',
120
- 'rainbow': 'قوس قزح', 'galaxy': 'مجرة', 'meteor': 'شهاب',
121
- 'rocket': 'صاروخ', 'love': 'حب', 'kiss': 'قبلة', 'hug': 'عناق',
122
- 'baby elephant': 'فيلا صغير', 'elephant': 'فيل',
123
- 'butterfly': 'فراشة', 'sunflower': 'دوار الشمس',
124
- 'lollipop': 'حلوى', 'cookie': 'بسكويت', 'donut': 'دونات',
125
- 'ice cream': 'آيس كريم', 'pizza': 'بيتزا',
126
- 'champagne': 'شمبانيا', 'wine': 'نبيذ',
127
- 'ring': 'خاتم', 'gem': 'جوهرة', 'pearl': 'لؤلؤ',
128
- 'teddy bear': 'دب', 'cat': 'قطة', 'dog': 'كلب',
129
- 'parrot': 'ببغاء', 'dove': 'حمام', 'swan': 'بط',
130
- 'hot air balloon': 'مظلة', 'spaceship': 'سفينة فضائية',
131
- 'comet': 'مذنب', 'planet': 'كوكب', 'moon': 'قمر', 'sun': 'شمس',
132
- 'ghost': 'شبح', 'skull': 'جمجمة',
133
- 'candy': 'حلوى', 'chocolate': 'شوكولاتة',
134
- 'wine bottle': 'زجاجة نبيذ', 'champagne bottle': 'زجاجة شمبانيا',
135
- 'birthday cake': 'كيكة عيد ميلاد', 'cake': 'كيكة',
136
- 'tshirt': 'تيشيرت', 'sneakers': 'أحذية',
137
- 'crown prince': 'ولي عهد', 'king': 'ملك', 'queen': 'ملكة',
138
- 'prince': 'أمير', 'princess': 'أميرة',
139
- 'rose garden': 'حديقة ورود', 'flower garden': 'حديقة زهور',
140
- 'treasure chest': 'كنز', 'magic wand': 'صباح سحري',
141
- 'lightning': 'برق', 'thunder': 'رعد',
142
- 'blue heart': 'قلب أزرق', 'purple heart': 'قلب بنفسجي',
143
- 'golden crown': 'تاج ذهبي', 'silver crown': 'تاج فضي',
144
- 'firework': 'ألعاب نارية', 'fireworks': 'ألعاب نارية',
145
- 'nevalyashka doll': 'دمية', 'dancing bear': 'دب راقص',
146
- 'lucky cat': 'قطة محظوظة', 'lucky': 'حظ',
147
- 'magic trick': 'حيلة سحرية', 'magic': 'سحر',
148
- 'rainbow rose': 'وردة قوس قزح', 'pink rose': 'وردة وردية',
149
- 'red rose': 'وردة حمراء', 'white rose': 'وردة بيضاء',
150
- 'blue rose': 'وردة زرقاء',
151
- 'golden ticket': 'تذكرة ذهبية', 'golden star': 'نجمة ذهبية',
152
- 'diamond ring': 'خاتم ماسي', 'diamond necklace': 'عقد ماسي',
153
- 'golden egg': 'بيضة ذهبية', 'golden heart': 'قلب ذهبي',
154
- 'crystal ball': 'كرة بلورية', 'magic book': 'كتاب سحري',
155
- 'tropical island': 'جزيرة استوائية', 'paradise': 'جنّة',
156
- 'royal carriage': 'عربة ملكية', 'castle': 'قصر',
157
- 'dragon flame': 'لهب التنين', 'phoenix': 'فينيक्स',
158
- 'mermaid': 'مرأة البحر', 'fairy': 'جنية',
159
- 'angel': 'ملاك', 'devil': 'شيطان',
160
- 'robot': 'روبوت', 'dinosaur': 'ديناصور',
161
- 'penguin': 'بطريق', 'panda': 'باندا', 'koala': 'كوالة',
162
- 'lion': 'أسد', 'eagle': 'نسر', 'wolf': 'ذئب',
163
- 'fox': 'ثعلب', 'rabbit': 'أرنب', 'hamster': 'هامستر',
164
- 'gold bar': 'سبيكة ذهب', 'gold coin': 'عملة ذهبية',
165
- 'money': 'مال', 'cash': 'كاش', 'dollar': 'دولار',
166
- 'money bag': 'كيس مال', 'money rain': 'مطر مال',
167
- 'diamond crown': 'تاج ماسي', 'diamond heart': 'قلب ماسي',
168
- 'super star': 'نجمة خارقة', 'mega star': 'نجمة عملاقة',
169
- 'cosmic rose': 'وردة كونية', 'stellar': 'نجمي',
170
- 'infinity': 'لا نهاية', 'universe': 'كون',
171
- 'supreme': 'علوي', 'ultimate': 'نهائي',
172
- 'legend': 'أسطوري', 'epic': 'ملحمي', 'mythic': 'خرافي',
173
- 'golden dragon': 'تنين ذهبي', 'silver dragon': 'تنين فضي',
174
- 'rainbow crown': 'تاج قوس قزح', 'diamond galaxy': 'مجرة ماسية',
175
- 'royal guard': 'حارس ملكي', 'royal': 'ملكي',
176
- 'neon heart': 'قلب نيون', 'neon star': 'نجمة نيون',
177
- 'pixel heart': 'قلب بيكسل', 'retro': 'ريترو',
178
- 'halo': 'هالة', 'wings': 'أجنحة',
179
- 'bow': 'قوس', 'arrow': 'سهم',
180
- 'sword': 'سيف', 'shield': 'درع',
181
- 'cherry': 'كرز', 'apple': 'تفاحة', 'grape': 'عنب',
182
- 'watermelon': 'بطيخ', 'orange': 'برتقالة', 'lemon': 'ليمون',
183
- 'strawberry': 'فراولة', 'banana': 'موز', 'peach': 'خوخ',
184
- 'cupcake': 'كعكة صغيرة', 'muffin': 'مافن', 'pie': 'فطيرة',
185
- 'bread': 'خبز', 'burger': 'برجر', 'fries': 'بطاطس مقلية',
186
- 'coffee': 'قهوة', 'tea': 'شاي', 'milk': 'حليب',
187
- 'beer': 'بيرة', 'cocktail': 'كوكتيل', 'whiskey': 'ويسكي',
188
- 'sparkler': 'شرارة', 'lantern': 'مصباح', 'candle': 'شمعة',
189
- 'bell': 'جرس', 'whistle': 'صفارة',
190
- 'balloon': 'بالون', 'ribbon': 'شريط',
191
- 'gift box': 'صندوق هدية', 'gift': 'هدية', 'present': 'هدية',
192
- 'music': 'موسيقى', 'song': 'أغنية', 'note': 'ملحوظة',
193
- 'paint': 'طلي', 'brush': 'فرشاة', 'palette': 'لوحة ألوان',
194
- 'camera': 'كاميرا', 'film': 'فيلم', 'microphone': 'ميكروفون',
195
- 'speaker': 'مكبر صوت', 'radio': 'راديو', 'tv': 'تلفاز',
196
- 'phone': 'هاتف', 'computer': 'كمبيوتر', 'gamepad': 'يد تحكم',
197
- 'trophy': 'كأس', 'medal': 'وسام', 'star badge': 'شارة نجمة',
198
- 'ribbon badge': 'شارة شريط', 'badge': 'شارة',
199
- 'flag': 'علم', 'banner': 'لافتة', 'balloon animal': 'بالون حيواني',
200
- 'party hat': 'قبعة حفلة', 'party popper': 'فرقعة حفلة',
201
- 'confetti': 'قصاصات ورقية', 'streamer': 'شريط ملون',
202
- 'clown': 'مهرج', 'jester': 'مضحك',
203
- 'wizard': 'ساحر', 'mage': 'كاهن',
204
- 'knight': 'فرس', 'ninja': 'نينجا', 'samurai': 'ساموراي',
205
- 'pirate': 'قراصنة', 'viking': 'فايكنغ', 'pharaoh': 'فرعون',
206
- 'ghost face': 'وجه شبح', 'pumpkin': 'قرعة',
207
- 'snowman': 'رجل ثلج', 'snowflake': 'رقصة ثلج',
208
- 'christmas tree': 'شجرة عيد الميلاد', 'stocking': 'جوارب عيد الميلاد',
209
- 'santa': 'سانتا', 'reindeer': 'أيل',
210
- 'easter egg': 'بيضة عيد الفصح', 'chicken': 'دجاجة',
211
- 'turkey': 'ديك رومي', 'corn': 'ذرة',
212
- 'flower': 'زهرة', 'blossom': 'ازهار', 'tulip': 'توليب',
213
- 'orchid': 'أوركيد', 'daisy': 'أرجوان', 'lily': 'زنبق',
214
- 'sunflower': 'دوار الشمس', 'daffodil': 'نرجس',
215
- 'palm tree': 'نخلة', 'cactus': 'صبار', 'mushroom': 'فطر',
216
- 'treasure': 'كنز', 'key': 'مفتاح', 'lock': 'قفل',
217
- 'anchor': 'مرساة', 'compass': 'بوصلة', 'map': 'خريطة',
218
- 'crown prince': 'ولي عهد', 'king': 'ملك', 'queen': 'ملكة',
219
  };
220
 
 
221
  function getCountryInfo(code) {
222
  if (!code) return { name: 'غير محدد', flag: '🌍' };
223
  const upperCode = code.toUpperCase();
@@ -226,7 +232,8 @@ function getCountryInfo(code) {
226
 
227
  function getGiftArabicName(englishName, giftId) {
228
  if (!englishName) {
229
- return GIFT_DIAMONDS[giftId] ? 'هدية (' + (GIFT_DIAMONDS[giftId]) + '💎)' : 'هدية';
 
230
  }
231
  const lower = englishName.toLowerCase().trim();
232
  if (GIFT_ARABIC[lower]) return GIFT_ARABIC[lower];
@@ -234,26 +241,46 @@ function getGiftArabicName(englishName, giftId) {
234
  }
235
 
236
  function getGiftDiamonds(data) {
237
- // ✅ الطريقة الصحيحة في v2: قراءة القيم من مصادر متعددة
238
- const diamondCount = data.diamondCount;
239
- const extDiamonds = data.extendedGiftInfo?.diamond_count;
240
- const giftId = data.giftId;
241
- const fromDict = GIFT_DIAMONDS[giftId];
242
-
243
- // الأولوية: diamondCount من الحدث > extendedGiftInfo > قاموس
244
- if (diamondCount && diamondCount > 0) return diamondCount;
245
- if (extDiamonds && extDiamonds > 0) return extDiamonds;
246
- if (fromDict) return fromDict;
247
-
248
- return 1; // قيمة افتراضية
 
 
 
 
 
 
 
 
 
249
  }
250
 
251
  function formatK(num) {
 
252
  if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
253
  if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
254
  return num.toString();
255
  }
256
 
 
 
 
 
 
 
 
 
 
 
257
  function getBaghdadTime() {
258
  return new Intl.DateTimeFormat('ar-IQ', {
259
  timeZone: 'Asia/Baghdad',
@@ -265,15 +292,16 @@ function getBaghdadTime() {
265
  }
266
 
267
  function generateProgressBar(ourScore, theirScore, length = 10) {
268
- const total = ourScore + theirScore;
269
  if (total === 0) return "⬜".repeat(length);
270
  const ourPercent = Math.min(
271
- Math.max(Math.round((ourScore / total) * length), 0),
272
  length
273
  );
274
  return "🟦".repeat(ourPercent) + "🟥".repeat(length - ourPercent);
275
  }
276
 
 
277
  function httpGet(url, headers = {}, timeout = 15000) {
278
  return new Promise((resolve, reject) => {
279
  const urlObj = new URL(url);
@@ -284,7 +312,7 @@ function httpGet(url, headers = {}, timeout = 15000) {
284
  path: urlObj.pathname + urlObj.search,
285
  method: 'GET',
286
  headers: {
287
- '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',
288
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
289
  'Accept-Language': 'en-US,en;q=0.9,ar;q=0.8',
290
  'Accept-Encoding': 'gzip, deflate',
@@ -308,7 +336,7 @@ function httpPost(url, payload, timeout = 15000) {
308
  return new Promise((resolve, reject) => {
309
  const urlObj = new URL(url);
310
  const protocol = urlObj.protocol === 'https:' ? https : http;
311
- const data = JSON.stringify(payload);
312
  const options = {
313
  hostname: urlObj.hostname,
314
  port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
@@ -316,7 +344,7 @@ function httpPost(url, payload, timeout = 15000) {
316
  method: 'POST',
317
  headers: {
318
  'Content-Type': 'application/json',
319
- 'Content-Length': Buffer.byteLength(data)
320
  },
321
  timeout: timeout
322
  };
@@ -327,11 +355,12 @@ function httpPost(url, payload, timeout = 15000) {
327
  });
328
  req.on('error', reject);
329
  req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
330
- req.write(data);
331
  req.end();
332
  });
333
  }
334
 
 
335
  async function getUserDataWithRegion(username) {
336
  try {
337
  const response = await httpGet('https://www.tiktok.com/@' + username);
@@ -357,10 +386,18 @@ async function getUserDataWithRegion(username) {
357
  return null;
358
  }
359
 
360
- let maxViewers = 0, totalLikes = 0, totalShares = 0, giftersMap = {};
361
- let pkActive = false, pkInfo = { opponentName: "", ourLikes: 0, theirLikes: 0 };
 
 
 
 
 
 
 
362
  let userCache = {};
363
 
 
364
  async function sendToTelegram(text, photoUrl = null, buttons = null) {
365
  try {
366
  const payload = {
@@ -397,99 +434,104 @@ async function resolveUser(username) {
397
  return null;
398
  }
399
 
400
- // ✅ v2 API
 
401
  let tiktokConnection = new TikTokLiveConnection(TIKTOK_USERNAME, {
402
  processInitialData: true,
403
  enableExtendedGiftInfo: true,
404
- webcastKernelVersion: 5,
405
  clientParams: {
406
  app_language: "ar-IQ",
407
  device_platform: "web"
408
  }
409
  });
410
 
 
411
  async function startRadar() {
412
  console.log('⏳ جاري البحث: ' + TIKTOK_USERNAME + '...');
413
  userCache = {};
414
  giftersMap = {};
415
  maxViewers = 0;
416
  totalLikes = 0;
 
417
  totalShares = 0;
418
  pkActive = false;
 
 
419
 
420
  const userData = await getUserDataWithRegion(TIKTOK_USERNAME);
421
  const countryInfo = getCountryInfo(userData?.region);
422
 
423
- tiktokConnection.connect().then(state => {
424
- const liveLink = 'https://www.tiktok.com/@' + TIKTOK_USERNAME + '/live';
 
425
 
426
- // ✅ جلب صورة الصاحب من عدة مسارات
427
  let avatarUrl = '';
428
- const roomOwner = state.roomInfo?.owner || null;
429
- if (roomOwner) {
430
- // محاولة عدة مسارات للصورة
431
- if (roomOwner.profilePicture) avatarUrl = roomOwner.profilePicture;
432
- else if (roomOwner.avatarLarge?.urlList?.[0]) avatarUrl = roomOwner.avatarLarge.urlList[0];
433
- else if (roomOwner.avatarLarge?.url?.[0]) avatarUrl = roomOwner.avatarLarge.url[0];
434
- else if (roomOwner.avatarThumb?.urlList?.[0]) avatarUrl = roomOwner.avatarThumb.urlList[0];
435
- else if (roomOwner.avatarThumb?.url?.[0]) avatarUrl = roomOwner.avatarThumb.url[0];
436
- else if (roomOwner.avatar?.urlList?.[0]) avatarUrl = roomOwner.avatar.urlList[0];
437
- else if (roomOwner.avatar?.url?.[0]) avatarUrl = roomOwner.avatar.url[0];
438
- else if (roomOwner.profilePictureUrl) avatarUrl = roomOwner.profilePictureUrl;
439
- else if (roomOwner.profileThumbnail) avatarUrl = roomOwner.profileThumbnail;
 
 
 
440
  }
441
- // fallback
442
- if (!avatarUrl && state.roomInfo?.sharedCover) avatarUrl = state.roomInfo.sharedCover;
443
- if (!avatarUrl && state.roomInfo?.coverUrl) avatarUrl = state.roomInfo.coverUrl;
444
 
445
  const displayName = userData?.nickname || TIKTOK_USERNAME;
446
- const verifiedBadge = userData?.verified ? '✅' : '';
447
 
448
- // ✅ تنسيق أفخم لبداية البث
449
  const msg = '🔴 ' + displayName + verifiedBadge + '\n\n' +
450
  '🌐 @' + TIKTOK_USERNAME + '\n' +
451
  countryInfo.flag + ' ' + countryInfo.name + '\n' +
452
  '⏰ ' + getBaghdadTime();
453
 
454
  sendToTelegram(msg, avatarUrl || undefined, [[{ text: "📺 دخول البث المباشر", url: liveLink }]]);
455
-
456
- console.log('✅ متصل! البلد: ' + countryInfo.name);
457
  console.log('📸 صورة: ' + (avatarUrl ? 'متوفرة' : 'غير متوفرة'));
458
- }).catch(err => {
459
- console.log('🔎 مغلق: ' + err.message);
460
  setTimeout(startRadar, 60000);
461
- });
462
  }
463
 
464
- // ✅ الأحداث الأساسية
 
 
465
  tiktokConnection.on(WebcastEvent.ROOM_USER, data => {
466
  const count = data.viewerCount || 0;
467
  if (count > maxViewers) maxViewers = count;
468
  });
469
 
 
470
  tiktokConnection.on(WebcastEvent.LIKE, data => {
471
- totalLikes += data.likeCount || 0;
 
 
472
  if (pkActive) {
473
- pkInfo.ourLikes += data.likeCount || 0;
474
  }
475
  });
476
 
477
- // ✅ مشاركة البث
478
  tiktokConnection.on(WebcastEvent.SOCIAL, data => {
479
  totalShares++;
480
  console.log('↪️ مشاركة!');
481
  });
482
 
483
- // ✅ تعليقات الشات
484
  tiktokConnection.on(WebcastEvent.CHAT, data => {
485
  // لا نرسل إشعارات لتجنب السبام
486
  });
487
 
488
- // ✅ ========== الهدايا - الإصلاح الكامل ==========
489
  tiktokConnection.on(WebcastEvent.GIFT, async data => {
490
- // ✅ في v2: البيانات في مستوى علوي مباشرة
491
- // data.uniqueId, data.nickname, data.diamondCount, data.giftName, data.giftId, etc.
492
-
493
  const gifterUsername = data.uniqueId || '';
494
  const nickname = data.nickname || '';
495
  const giftId = data.giftId || 0;
@@ -498,30 +540,28 @@ tiktokConnection.on(WebcastEvent.GIFT, async data => {
498
  const giftType = data.giftType || 0;
499
  const repeatEnd = data.repeatEnd;
500
 
501
- // تجاهل تحديثات الستريك المستمر - نأخذ فقط النهاية
502
  if (giftType === 1 && !repeatEnd) return;
503
 
504
- // ✅ حساب قيمة الهدية من عدة مصادر
505
  const baseDiamonds = getGiftDiamonds(data);
506
  const giftCost = baseDiamonds * repeatCount;
507
 
508
  // ✅ الاسم بالعربي
509
  const arabicName = getGiftArabicName(giftNameEn, giftId);
510
 
511
- // طباعة للتشخيص
512
- console.log('��� ' + gifterUsername + ' → ' + arabicName + ' (ID:' + giftId + ') x' + repeatCount +
513
- ' = ' + baseDiamonds + '×' + repeatCount + ' = ' + giftCost + ' 💎' +
514
- ' [dc=' + data.diamondCount + ' ext=' + (data.extendedGiftInfo?.diamond_count || 'none') + ']');
515
 
516
  if (!gifterUsername) {
517
- console.log('⚠️ هدية بدون اسم مستخدم');
518
  return;
519
  }
520
 
521
  const userId = data.userId || gifterUsername;
522
  if (!giftersMap[userId]) {
523
  giftersMap[userId] = {
524
- name: nickname,
525
  username: gifterUsername,
526
  coins: 0,
527
  region: null,
@@ -530,21 +570,21 @@ tiktokConnection.on(WebcastEvent.GIFT, async data => {
530
  }
531
  giftersMap[userId].coins += giftCost;
532
 
533
- // ✅ جلب بيانات الدولة من صفحة المرسِل
534
  const userRegionData = await resolveUser(gifterUsername);
535
  let region = null;
536
- let displayName = nickname;
537
 
538
  if (userRegionData && userRegionData.region) {
539
  region = userRegionData.region;
540
- displayName = userRegionData.nickname || nickname;
541
  giftersMap[userId].region = region;
542
  }
543
 
544
  const gc = getCountryInfo(region);
545
  giftersMap[userId].flag = gc.flag;
546
 
547
- // ✅ تنسيق الرسالة
548
  const repeatText = repeatCount > 1 ? ' ×' + repeatCount : '';
549
  const msg = '🎁 ' + arabicName + repeatText + '\n\n' +
550
  gc.flag + ' ' + displayName + '\n' +
@@ -558,16 +598,65 @@ tiktokConnection.on(WebcastEvent.GIFT, async data => {
558
  ]]);
559
  });
560
 
561
- // ✅ تتبع الأحداث
562
- tiktokConnection.on(WebcastEvent.CONNECTED, state => {
563
- console.log('✅ متصل بالغرفة:', state.roomId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
  });
565
 
 
566
  tiktokConnection.on(WebcastEvent.DISCONNECTED, () => {
567
  console.log('❌ تم القطع');
568
  });
569
 
570
- // 🔥 أحداث PK
 
 
 
 
 
571
  tiktokConnection.on('pkStart', data => {
572
  pkActive = true;
573
  pkInfo = { opponentName: data.opponentNickname || 'منافس', ourLikes: 0, theirLikes: 0 };
@@ -592,13 +681,16 @@ tiktokConnection.on('pkEnd', data => {
592
  );
593
  });
594
 
595
- // ✅ نهاية البث
596
  tiktokConnection.on('streamEnd', () => {
 
 
597
  const top = getTopGifters(giftersMap, 5);
598
  const medals = ['🥇', '🥈', '🥉', '4️⃣', '5️⃣'];
599
  let topText = top.map((g, i) =>
600
- medals[i] + ' ' + (g.flag || '🌍') + ' ' + g.name + ': ' + formatK(g.coins) + ' 💎'
601
- ).join('\n') || '> لا داعمين';
 
602
 
603
  const countryStats = {};
604
  Object.values(giftersMap).forEach(g => {
@@ -611,21 +703,24 @@ tiktokConnection.on('streamEnd', () => {
611
  .slice(0, 3)
612
  .map(([r, c], i) =>
613
  ['👑', '🥈', '🥉'][i] + ' ' + getCountryInfo(r).flag + ' ' +
614
- getCountryInfo(r).name + ': ' + formatK(c) + ' 💎'
615
- ).join('\n') || '> لا بيانات';
616
 
617
  sendToTelegram(
618
  '📊 التقرير النهائي\n\n' +
619
- '📈 أعلى مشاهدات: ' + formatK(maxViewers) + '\n' +
 
620
  '❤️ إعجابات: ' + formatK(totalLikes) + '\n' +
621
- '↪️ مشاركات: ' + formatK(totalShares) + '\n\n' +
622
- '🏆 الداعمين:\n' + topText + '\n\n' +
623
- '🌍 توزيع حسب البلد:\n' + countryRanking
 
624
  );
625
 
626
  setTimeout(startRadar, 60000);
627
  });
628
 
 
629
  const server = http.createServer((req, res) => {
630
  res.writeHead(200, { 'Content-Type': 'text/plain' });
631
  res.end('OK');
 
12
 
13
  dns.setServers(['8.8.8.8']);
14
 
15
+ // ====== قاموس الدول ======
16
  const COUNTRY_FLAGS = {
17
  'SA': { name: 'السعودية', flag: '🇸🇦' },
18
  'EG': { name: 'مصر', flag: '🇪🇬' },
 
82
  'IE': { name: 'أيرلندا', flag: '🇮🇪' },
83
  };
84
 
85
+ // ====== قاموس الهدايا بالعربي ======
86
+ const GIFT_ARABIC = {
87
+ 'rose':'وردة','rosebud':'برعم ورد','smile':'ابتسامة','heart':'قلب',
88
+ 'thumbs up':'إبهام','thumbsup':'إبهام','star':'نجمة','fire':'نار',
89
+ 'flame':'لهب','crown':'تاج','diamond':'ماسة','tiger':'نمر',
90
+ 'dragon':'تنين','unicorn':'أحادي القرن','rainbow':'قوس قزح',
91
+ 'galaxy':'مجرة','meteor':'شهاب','rocket':'صاروخ','love':'حب',
92
+ 'kiss':'قبلة','hug':'عناق','baby elephant':'فيلا صغير','elephant':'فيل',
93
+ 'butterfly':'فراشة','sunflower':'دوار الشمس','lollipop':'حلوى',
94
+ 'cookie':'بسكويت','donut':'دونات','ice cream':'آيس كريم','pizza':'بيتزا',
95
+ 'champagne':'شمبانيا','wine':'نبيذ','ring':'خاتم','gem':'جوهرة',
96
+ 'pearl':'لؤلؤ','teddy bear':'دب','cat':'قطة','dog':'كلب',
97
+ 'parrot':'ببغاء','dove':'حمام','swan':'بط','hot air balloon':'مظلة',
98
+ 'spaceship':'سفينة فضائية','comet':'مذنب','planet':'كوكب',
99
+ 'moon':'قمر','sun':'شمس','ghost':'شبح','skull':'جمجمة',
100
+ 'candy':'حلوى','chocolate':'شوكولاتة','birthday cake':'كيكة عيد ميلاد',
101
+ 'cake':'كيكة','tshirt':'تيشيرت','sneakers':'أحذية','king':'ملك',
102
+ 'queen':'ملكة','prince':'أمير','princess':'أميرة',
103
+ 'rose garden':'حديقة ورود','flower garden':'حديقة زهور',
104
+ 'treasure chest':'كنز','lightning':'برق','thunder':'رعد',
105
+ 'blue heart':'قلب أزرق','purple heart':'قلب بنفسجي',
106
+ 'golden crown':'تاج ذهبي','silver crown':'تاج فضي',
107
+ 'firework':'ألعاب نارية','fireworks':'ألعاب نارية',
108
+ 'nevalyashka doll':'دمية','dancing bear':'دب راقص',
109
+ 'lucky cat':'قطة محظوظة','magic':'سحر',
110
+ 'rainbow rose':'وردة قوس قزح','pink rose':'وردة وردية',
111
+ 'red rose':'وردة حمراء','white rose':'وردة بيضاء','blue rose':'وردة زرقاء',
112
+ 'golden ticket':'تذكرة ذهبية','golden star':'نجمة ذهبية',
113
+ 'diamond ring':'خاتم ماسي','diamond necklace':'عقد ماسي',
114
+ 'golden egg':'بيضة ذهبية','golden heart':'قلب ذهبي',
115
+ 'crystal ball':'كرة بلورية','tropical island':'جزيرة استوائية',
116
+ 'royal carriage':'عربة ملكية','castle':'قصر','dragon flame':'لهب التنين',
117
+ 'phoenix':'فيني克斯','mermaid':'مرأة البحر','fairy':'جنية',
118
+ 'angel':'ملاك','devil':'شيطان','robot':'روبوت','dinosaur':'ديناصور',
119
+ 'penguin':'بطريق','panda':'باندا','koala':'كوالة','lion':'أسد',
120
+ 'eagle':'نسر','wolf':'ذئب','fox':'ثعلب','rabbit':'أرنب',
121
+ 'gold bar':'سبيكة ذهب','gold coin':'عملة ذهبية','money bag':'كيس مال',
122
+ 'diamond crown':'تاج ماسي','diamond heart':'قلب ماسي',
123
+ 'super star':'نجمة خارقة','mega star':'نجمة عملاقة',
124
+ 'cosmic rose':'وردة كونية','infinity':'لا نهاية','universe':'كون',
125
+ 'supreme':'علوي','ultimate':'نهائي','legend':'أسطوري',
126
+ 'epic':'ملحمي','mythic':'خرافي','golden dragon':'تنين ذهبي',
127
+ 'rainbow crown':'تاج قوس قزح','diamond galaxy':'مجرة ماسية',
128
+ 'halo':'هالة','wings':'أجنحة','bow':'قوس','arrow':'سهم',
129
+ 'sword':'سيف','shield':'درع','cherry':'كرز','apple':'تفاحة',
130
+ 'grape':'عنب','watermelon':'بطيخ','strawberry':'فراولة',
131
+ 'banana':'موز','peach':'خوخ','cupcake':'كعكة صغيرة',
132
+ 'sparkler':'شرارة','lantern':'مصباح','candle':'شمعة',
133
+ 'balloon':'بالون','ribbon':'شريط','gift box':'صندوق هدية',
134
+ 'gift':'هدية','present':'هدية','music':'موسيقى',
135
+ 'trophy':'كأس','medal':'وسام','flag':'علم',
136
+ 'party hat':'قبعة حفلة','confetti':'قصاصات ورقية',
137
+ 'wizard':'ساحر','knight':'فرس','ninja':'نينجا',
138
+ 'pirate':'قراصنة','pumpkin':'قرعة','snowman':'رجل ثلج',
139
+ 'snowflake':'رقصة ثلج','santa':'سانتا','reindeer':'أيل',
140
+ 'flower':'زهرة','blossom':'ازهار','tulip':'توليب',
141
+ 'orchid':'أوركيد','daisy':'أرجوان','lily':'زنبق',
142
+ 'palm tree':'نخلة','cactus':'صبار','mushroom':'فطر',
143
+ 'crown prince':'ولي عهد','treasure':'كنز',
144
+ 'wine bottle':'زجاجة نبيذ','champagne bottle':'زجاجة شمبانيا',
145
+ 'magic wand':'صباح سحري','magic trick':'حيلة سحرية',
146
+ 'neon heart':'قلب نيون','neon star':'نجمة نيون',
147
+ 'retro':'ريترو','pixel heart':'قلب بيكسل',
148
+ 'golden heart':'قلب ذهبي','silver heart':'قلب فضي',
149
+ 'black heart':'قلب أسود','broken heart':'قلب مكسور',
150
+ 'fire heart':'قلب محترق','sparkling heart':'قلب لامع',
151
+ 'yellow heart':'قلب أصفر','green heart':'قلب أخضر',
152
+ 'orange heart':'قلب برتقالي','brown heart':'قلب بني',
153
+ 'light blue heart':'قلب سماوي','gray heart':'قلب رمادي',
154
+ '100':'100','money':'مال','cash':'كاش','dollar':'دولار',
155
+ 'money rain':'مطر مال','viking':'فايكنغ','pharaoh':'فرعون',
156
+ 'easter egg':'بيضة عيد الفصح','chicken':'دجاجة',
157
+ 'ghost face':'وجه شبح','christmas tree':'شجرة عيد الميلاد',
158
+ 'easter bunny':'أرنب عيد الفصح','jack o lantern':'جوجه قرعة',
159
+ 't-rex':'تي-ريكس','skeleton':'هيكل عظمي',
160
+ 'vampire':'مدمن دم','zombie':'زومبي',
161
+ 'alien':'غريب','wizard hat':'قبعة ساحر',
162
+ 'top hat':'قبعة عالية','bow tie':'ربطة عنق',
163
+ 'sunglasses':'نظارة شمسية','cool':'بارد',
164
+ 'thumbs up':'إبهام للأعلى','clap':'تصفيق',
165
+ 'pray':'دعاء','clap hands':'تصفيق',
166
+ 'folded hands':'يدان مطويتان','raising hands':'أيدي مرفوعة',
167
+ 'handshake':'مصافحة','victory':'انتصار',
168
+ 'crossed fingers':'أصابع متقاطعة','pinching hand':'قبضة صغيرة',
169
+ 'love you':'أحبك','call me':'اتصل بي',
170
+ 'ok hand':'حسناً','raised hand':'يد مرفوعة',
171
+ 'waving hand':'يد متموجة','flexed biceps':'بطن مشدود',
172
+ 'selfie':'سيلفي','nail polish':'طلاء أظافر',
173
+ 'lipstick':'أحمر شفاه','kiss mark':'علامة قبلة',
174
+ 'lipstick kiss':'قبلة أحمر شفاه','heart eyes':'عينات قلب',
175
+ 'starry eyes':'عينات نجمية','drooling face':'وجه يتلوى',
176
+ 'thinking':'فكر','nerd':'مهووس','sunglasses face':'وجه بنظارة',
177
+ 'mask':'قناع','thermometer':'مقياس حرارة',
178
+ 'bandage':'ضماد':'sneezing face':'وجه يعطس',
179
+ 'face with head bandage':'وجه بضماد على الرأس',
180
+ 'nauseated face':'وجه غاضب','vomiting face':'وجه يتقيء',
181
+ 'cool face':'وجه بارد','party face':'وجه حفلة',
182
+ 'disguised face':'وجه متخفٍ','cowboy hat face':'وجه بقبعة',
183
+ 'exploding head':'رأس ينفجر','face with diamonds':'وجه بماسات',
184
+ 'lying face':'وجه يكذب','melting face':'وجه يذوب',
185
  };
186
 
187
+ // ====== قيم الهدايا بالدiamonds ======
188
+ const GIFT_VALUES = {
189
+ 5953:25, 5952:1, 5951:5, 5950:10, 5949:15, 5948:20,
190
+ 5947:30, 5946:50, 5945:100, 5944:200, 5943:500,
191
+ 5942:1000, 5941:2000, 5940:5000, 5939:10000,
192
+ 5938:25000, 5937:50000, 5936:100000,
193
+ 5935:1, 5934:3, 5933:5, 5932:10, 5931:15,
194
+ 5930:20, 5929:30, 5928:40, 5927:50, 5926:60,
195
+ 5925:80, 5924:100, 5923:150, 5922:200, 5921:300,
196
+ 5920:400, 5919:500, 5918:700, 5917:1000,
197
+ 5916:1500, 5915:2000, 5914:3000, 5913:5000,
198
+ 5912:10000, 5911:20000, 5910:50000, 5909:100000,
199
+ 5908:250000, 5907:500000, 5906:1000000,
200
+ 5905:10, 5904:25, 5903:50, 5902:100,
201
+ 5901:200, 5900:500, 5899:1000, 5898:2000,
202
+ 5897:5000, 5896:10000, 5895:20000, 5894:50000,
203
+ 5893:100000, 5892:250000, 5891:500000, 5890:1000000,
204
+ 5729:1, 5728:5, 5727:10, 5726:15, 5725:20,
205
+ 5724:30, 5723:50, 5722:100, 5721:200, 5720:500,
206
+ 5719:1000, 5718:2000, 5717:5000, 5716:10000,
207
+ 5715:25000, 5714:50000, 5713:100000,
208
+ 5712:250000, 5711:500000, 5710:1000000,
209
+ 5972:1, 5971:1, 5970:1, 5969:1, 5968:3,
210
+ 5967:5, 5966:10, 5965:15, 5964:20, 5963:30,
211
+ 5962:40, 5961:50, 5960:100,
212
+ 1817:1, 1816:1, 1815:1, 1814:1, 1813:1,
213
+ 1812:1, 1811:1, 1810:5, 1809:5, 1808:5,
214
+ 1807:5, 1806:10, 1805:10, 1804:10,
215
+ 1803:15, 1802:20, 1801:25, 1800:30,
216
+ 1799:35, 1798:40, 1797:50, 1796:60,
217
+ 1795:70, 1794:80, 1793:90, 1792:100,
218
+ 1791:150, 1790:200, 1789:250, 1788:300,
219
+ 1787:400, 1786:500, 1785:700, 1784:1000,
220
+ 1783:1500, 1782:2000, 1781:3000, 1780:5000,
221
+ 1779:7000, 1778:10000, 1777:15000, 1776:20000,
222
+ 1775:30000, 1774:50000, 1773:75000, 1772:100000,
223
+ 1807:5000, 1808:5000, 1809:3000, 1810:3000,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  };
225
 
226
+ // ====== دوال مساعدة ======
227
  function getCountryInfo(code) {
228
  if (!code) return { name: 'غير محدد', flag: '🌍' };
229
  const upperCode = code.toUpperCase();
 
232
 
233
  function getGiftArabicName(englishName, giftId) {
234
  if (!englishName) {
235
+ const val = GIFT_VALUES[giftId];
236
+ return val ? '💎' + val : 'هدية';
237
  }
238
  const lower = englishName.toLowerCase().trim();
239
  if (GIFT_ARABIC[lower]) return GIFT_ARABIC[lower];
 
241
  }
242
 
243
  function getGiftDiamonds(data) {
244
+ // ✅ v2: diamondCount في مستوى علوي
245
+ const dc = data.diamondCount;
246
+ if (dc && dc > 0) return dc;
247
+
248
+ // ✅ من extendedGiftInfo
249
+ const extDc = data.extendedGiftInfo?.diamond_count;
250
+ if (extDc && extDc > 0) return extDc;
251
+
252
+ // ✅ من قيمة الهدية في القاموس
253
+ const gid = data.giftId;
254
+ if (GIFT_VALUES[gid]) return GIFT_VALUES[gid];
255
+
256
+ // ✅ من coinValue في gift
257
+ const coinVal = data.gift?.coinValue;
258
+ if (coinVal && coinVal > 0) return coinVal;
259
+
260
+ // ✅ من diamondCount في gift
261
+ const giftDc = data.gift?.diamondCount;
262
+ if (giftDc && giftDc > 0) return giftDc;
263
+
264
+ return 1; // افتراضي
265
  }
266
 
267
  function formatK(num) {
268
+ if (!num || isNaN(num) || num === 0) return '0';
269
  if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
270
  if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
271
  return num.toString();
272
  }
273
 
274
+ function formatDuration(seconds) {
275
+ if (!seconds || seconds <= 0) return 'دقيقة واحدة';
276
+ const h = Math.floor(seconds / 3600);
277
+ const m = Math.floor((seconds % 3600) / 60);
278
+ const parts = [];
279
+ if (h > 0) parts.push(h + ' ساعة');
280
+ if (m > 0) parts.push(m + ' دقيقة');
281
+ return parts.join(' و ') || 'أقل من دقيقة';
282
+ }
283
+
284
  function getBaghdadTime() {
285
  return new Intl.DateTimeFormat('ar-IQ', {
286
  timeZone: 'Asia/Baghdad',
 
292
  }
293
 
294
  function generateProgressBar(ourScore, theirScore, length = 10) {
295
+ const total = (ourScore || 0) + (theirScore || 0);
296
  if (total === 0) return "⬜".repeat(length);
297
  const ourPercent = Math.min(
298
+ Math.max(Math.round(((ourScore || 0) / total) * length), 0),
299
  length
300
  );
301
  return "🟦".repeat(ourPercent) + "🟥".repeat(length - ourPercent);
302
  }
303
 
304
+ // ====== HTTP Functions ======
305
  function httpGet(url, headers = {}, timeout = 15000) {
306
  return new Promise((resolve, reject) => {
307
  const urlObj = new URL(url);
 
312
  path: urlObj.pathname + urlObj.search,
313
  method: 'GET',
314
  headers: {
315
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.0.0 Safari/537.36',
316
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
317
  'Accept-Language': 'en-US,en;q=0.9,ar;q=0.8',
318
  'Accept-Encoding': 'gzip, deflate',
 
336
  return new Promise((resolve, reject) => {
337
  const urlObj = new URL(url);
338
  const protocol = urlObj.protocol === 'https:' ? https : http;
339
+ const body = JSON.stringify(payload);
340
  const options = {
341
  hostname: urlObj.hostname,
342
  port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
 
344
  method: 'POST',
345
  headers: {
346
  'Content-Type': 'application/json',
347
+ 'Content-Length': Buffer.byteLength(body)
348
  },
349
  timeout: timeout
350
  };
 
355
  });
356
  req.on('error', reject);
357
  req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
358
+ req.write(body);
359
  req.end();
360
  });
361
  }
362
 
363
+ // ====== جلب بيانات المستخدم + الدولة ======
364
  async function getUserDataWithRegion(username) {
365
  try {
366
  const response = await httpGet('https://www.tiktok.com/@' + username);
 
386
  return null;
387
  }
388
 
389
+ // ====== متغيرات عامة ======
390
+ let maxViewers = 0;
391
+ let totalLikes = 0;
392
+ let totalShares = 0;
393
+ let totalLikesEvents = 0;
394
+ let streamStartTime = null;
395
+ let giftersMap = {};
396
+ let pkActive = false;
397
+ let pkInfo = { opponentName: "", ourLikes: 0, theirLikes: 0 };
398
  let userCache = {};
399
 
400
+ // ====== إرسال تليقرام ======
401
  async function sendToTelegram(text, photoUrl = null, buttons = null) {
402
  try {
403
  const payload = {
 
434
  return null;
435
  }
436
 
437
+ // ====== الاتصال بـ TikTok Live ======
438
+ // ✅ استخدام TikTokLiveConnection بدون webcastKernelVersion
439
  let tiktokConnection = new TikTokLiveConnection(TIKTOK_USERNAME, {
440
  processInitialData: true,
441
  enableExtendedGiftInfo: true,
 
442
  clientParams: {
443
  app_language: "ar-IQ",
444
  device_platform: "web"
445
  }
446
  });
447
 
448
+ // ====== تشغيل الرادار ======
449
  async function startRadar() {
450
  console.log('⏳ جاري البحث: ' + TIKTOK_USERNAME + '...');
451
  userCache = {};
452
  giftersMap = {};
453
  maxViewers = 0;
454
  totalLikes = 0;
455
+ totalLikesEvents = 0;
456
  totalShares = 0;
457
  pkActive = false;
458
+ pkInfo = { opponentName: "", ourLikes: 0, theirLikes: 0 };
459
+ streamStartTime = Date.now();
460
 
461
  const userData = await getUserDataWithRegion(TIKTOK_USERNAME);
462
  const countryInfo = getCountryInfo(userData?.region);
463
 
464
+ try {
465
+ const state = await tiktokConnection.connect();
466
+ console.log('✅ متصل بالغرفة!');
467
 
468
+ const liveLink = 'https://www.tiktok.com/@' + TIKTOK_USERNAME + '/live';
469
  let avatarUrl = '';
470
+ const owner = state.roomInfo?.owner || null;
471
+ if (owner) {
472
+ if (owner.profilePicture) avatarUrl = owner.profilePicture;
473
+ else if (owner.profilePictureUrl) avatarUrl = owner.profilePictureUrl;
474
+ else if (owner.profileThumbnail) avatarUrl = owner.profileThumbnail;
475
+ else if (owner.avatarLarge?.urlList?.[0]) avatarUrl = owner.avatarLarge.urlList[0];
476
+ else if (owner.avatarLarge?.url?.[0]) avatarUrl = owner.avatarLarge.url[0];
477
+ else if (owner.avatarThumb?.urlList?.[0]) avatarUrl = owner.avatarThumb.urlList[0];
478
+ else if (owner.avatarThumb?.url?.[0]) avatarUrl = owner.avatarThumb.url[0];
479
+ else if (owner.avatar?.urlList?.[0]) avatarUrl = owner.avatar.urlList[0];
480
+ else if (owner.avatar?.url?.[0]) avatarUrl = owner.avatar.url[0];
481
+ else if (owner.profilePictureLarge?.url?.[0]) avatarUrl = owner.profilePictureLarge.url[0];
482
+ }
483
+ if (!avatarUrl) {
484
+ avatarUrl = state.roomInfo?.sharedCover || state.roomInfo?.coverUrl || '';
485
  }
 
 
 
486
 
487
  const displayName = userData?.nickname || TIKTOK_USERNAME;
488
+ const verifiedBadge = userData?.verified ? ' ✅' : '';
489
 
 
490
  const msg = '🔴 ' + displayName + verifiedBadge + '\n\n' +
491
  '🌐 @' + TIKTOK_USERNAME + '\n' +
492
  countryInfo.flag + ' ' + countryInfo.name + '\n' +
493
  '⏰ ' + getBaghdadTime();
494
 
495
  sendToTelegram(msg, avatarUrl || undefined, [[{ text: "📺 دخول البث المباشر", url: liveLink }]]);
496
+ console.log('🌍 البلد: ' + countryInfo.name);
 
497
  console.log('📸 صورة: ' + (avatarUrl ? 'متوفرة' : 'غير متوفرة'));
498
+ } catch (err) {
499
+ console.log('🔎 مغلق: ' + (err.message || err));
500
  setTimeout(startRadar, 60000);
501
+ }
502
  }
503
 
504
+ // ====== الأحداث ======
505
+
506
+ // ✅ عدد المشاهدين
507
  tiktokConnection.on(WebcastEvent.ROOM_USER, data => {
508
  const count = data.viewerCount || 0;
509
  if (count > maxViewers) maxViewers = count;
510
  });
511
 
512
+ // ✅ الإعجابات
513
  tiktokConnection.on(WebcastEvent.LIKE, data => {
514
+ totalLikesEvents++;
515
+ const lc = data.likeCount || 0;
516
+ if (lc > 0) totalLikes += lc;
517
  if (pkActive) {
518
+ pkInfo.ourLikes += lc;
519
  }
520
  });
521
 
522
+ // ✅ مشاركة
523
  tiktokConnection.on(WebcastEvent.SOCIAL, data => {
524
  totalShares++;
525
  console.log('↪️ مشاركة!');
526
  });
527
 
528
+ // ✅ تعليقات
529
  tiktokConnection.on(WebcastEvent.CHAT, data => {
530
  // لا نرسل إشعارات لتجنب السبام
531
  });
532
 
533
+ // ✅ ========== الهدايا ==========
534
  tiktokConnection.on(WebcastEvent.GIFT, async data => {
 
 
 
535
  const gifterUsername = data.uniqueId || '';
536
  const nickname = data.nickname || '';
537
  const giftId = data.giftId || 0;
 
540
  const giftType = data.giftType || 0;
541
  const repeatEnd = data.repeatEnd;
542
 
543
+ // تجاهل تحديثات الستريك
544
  if (giftType === 1 && !repeatEnd) return;
545
 
546
+ // ✅ القيمة
547
  const baseDiamonds = getGiftDiamonds(data);
548
  const giftCost = baseDiamonds * repeatCount;
549
 
550
  // ✅ الاسم بالعربي
551
  const arabicName = getGiftArabicName(giftNameEn, giftId);
552
 
553
+ console.log('🎁 ' + gifterUsername + ' → ' + arabicName + ' (ID:' + giftId + ') ×' +
554
+ repeatCount + ' = ' + giftCost + '💎 [dc:' + data.diamondCount + ']');
 
 
555
 
556
  if (!gifterUsername) {
557
+ console.log('⚠️ هدية بدون اسم');
558
  return;
559
  }
560
 
561
  const userId = data.userId || gifterUsername;
562
  if (!giftersMap[userId]) {
563
  giftersMap[userId] = {
564
+ name: nickname || gifterUsername,
565
  username: gifterUsername,
566
  coins: 0,
567
  region: null,
 
570
  }
571
  giftersMap[userId].coins += giftCost;
572
 
573
+ // ✅ جلب بيانات الدولة
574
  const userRegionData = await resolveUser(gifterUsername);
575
  let region = null;
576
+ let displayName = nickname || gifterUsername;
577
 
578
  if (userRegionData && userRegionData.region) {
579
  region = userRegionData.region;
580
+ displayName = userRegionData.nickname || displayName;
581
  giftersMap[userId].region = region;
582
  }
583
 
584
  const gc = getCountryInfo(region);
585
  giftersMap[userId].flag = gc.flag;
586
 
587
+ // ✅ الرسالة
588
  const repeatText = repeatCount > 1 ? ' ×' + repeatCount : '';
589
  const msg = '🎁 ' + arabicName + repeatText + '\n\n' +
590
  gc.flag + ' ' + displayName + '\n' +
 
598
  ]]);
599
  });
600
 
601
+ // ✅ ========== المشرفين ==========
602
+ tiktokConnection.on(WebcastEvent.MEMBER, async data => {
603
+ const memberUsername = data.uniqueId || '';
604
+ if (!memberUsername) return;
605
+
606
+ // ✅ فقط نكشف الدولة، ما نرسل إشعار دخول عادي
607
+ // لكن نرسل لو كان مشرف أو VIP
608
+ const memberData = await resolveUser(memberUsername);
609
+ if (memberData) {
610
+ userCache[memberUsername] = memberData;
611
+ }
612
+ });
613
+
614
+ // ✅ متابعة جديدة
615
+ tiktokConnection.on(WebcastEvent.FOLLOW, async data => {
616
+ const followUsername = data.uniqueId || '';
617
+ if (!followUsername) return;
618
+
619
+ console.log('➕ متابعة من: ' + followUsername);
620
+ const followData = await resolveUser(followUsername);
621
+ let region = null;
622
+ let displayName = data.nickname || followUsername;
623
+
624
+ if (followData) {
625
+ region = followData.region;
626
+ displayName = followData.nickname || displayName;
627
+ userCache[followUsername] = followData;
628
+ }
629
+
630
+ const gc = getCountryInfo(region);
631
+ const msg = '➕ متابع جديد!\n\n' +
632
+ gc.flag + ' ' + displayName + '\n' +
633
+ '📱 @' + followUsername + '\n' +
634
+ '🌍 ' + gc.name;
635
+
636
+ sendToTelegram(msg);
637
+ });
638
+
639
+ // ✅ ========== نهاية البث ==========
640
+ tiktokConnection.on(WebcastEvent.ROOM_STATS, data => {
641
+ // تحديث الإحصائيات من TikTok مباشرة
642
+ if (data.totalLikeCount) {
643
+ totalLikes = data.totalLikeCount;
644
+ }
645
+ console.log('📊 إحصائيات: مشاهدات=' + (data.viewerCount || maxViewers) +
646
+ ' إعجابات=' + totalLikes + ' مشاركات=' + totalShares);
647
  });
648
 
649
+ // ✅ Disconnect
650
  tiktokConnection.on(WebcastEvent.DISCONNECTED, () => {
651
  console.log('❌ تم القطع');
652
  });
653
 
654
+ // ✅ Connected
655
+ tiktokConnection.on(WebcastEvent.CONNECTED, state => {
656
+ console.log('✅ متصل بالغرفة:', state.roomId);
657
+ });
658
+
659
+ // 🔥 ========== أحداث PK ==========
660
  tiktokConnection.on('pkStart', data => {
661
  pkActive = true;
662
  pkInfo = { opponentName: data.opponentNickname || 'منافس', ourLikes: 0, theirLikes: 0 };
 
681
  );
682
  });
683
 
684
+ // ✅ ========== نهاية البث + التقرير ==========
685
  tiktokConnection.on('streamEnd', () => {
686
+ const streamDuration = streamStartTime ? formatDuration(Math.floor((Date.now() - streamStartTime) / 1000)) : 'غير معروف';
687
+
688
  const top = getTopGifters(giftersMap, 5);
689
  const medals = ['🥇', '🥈', '🥉', '4️⃣', '5️⃣'];
690
  let topText = top.map((g, i) =>
691
+ medals[i] + ' ' + (g.flag || '🌍') + ' ' + g.name + '\n' +
692
+ ' @' + g.username + ' → ' + formatK(g.coins) + ' 💎'
693
+ ).join('\n\n') || 'لا يوجد داعمين';
694
 
695
  const countryStats = {};
696
  Object.values(giftersMap).forEach(g => {
 
703
  .slice(0, 3)
704
  .map(([r, c], i) =>
705
  ['👑', '🥈', '🥉'][i] + ' ' + getCountryInfo(r).flag + ' ' +
706
+ getCountryInfo(r).name + ' → ' + formatK(c) + ' 💎'
707
+ ).join('\n') || 'لا بيانات';
708
 
709
  sendToTelegram(
710
  '📊 التقرير النهائي\n\n' +
711
+ '⏱️ مدة البث: ' + streamDuration + '\n' +
712
+ '👥 أعلى مشاهدات: ' + formatK(maxViewers) + '\n' +
713
  '❤️ إعجابات: ' + formatK(totalLikes) + '\n' +
714
+ '↪️ مشاركات: ' + formatK(totalShares) + '\n' +
715
+ '👥 إجمالي الداعمين: ' + Object.keys(giftersMap).length + '\n\n' +
716
+ '🏆 أقوى داعمين:\n\n' + topText + '\n\n' +
717
+ '🌍 توزيع حسب الدولة:\n' + countryRanking + '\n\n💤 بانتظار البث القادم...'
718
  );
719
 
720
  setTimeout(startRadar, 60000);
721
  });
722
 
723
+ // ====== الخادم ======
724
  const server = http.createServer((req, res) => {
725
  res.writeHead(200, { 'Content-Type': 'text/plain' });
726
  res.end('OK');