Reooiq commited on
Commit
4fbd484
ยท
verified ยท
1 Parent(s): 11046e6

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +7 -0
  2. README.md +35 -0
  3. bot.js +1315 -0
  4. package.json +9 -0
Dockerfile ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ FROM node:18-slim
2
+ WORKDIR /app
3
+ COPY package.json ./
4
+ RUN npm install
5
+ COPY . .
6
+ EXPOSE 7860
7
+ CMD ["node", "bot.js"]
README.md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: TikTok Radar v11
3
+ emoji: ๐Ÿ“ก
4
+ colorFrom: purple
5
+ colorTo: blue
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ ---
10
+
11
+ # ๐Ÿ“ก TikTok Radar v11.0 - ุงู„ู†ุณุฎุฉ ุงู„ู…ุญุณู‘ู†ุฉ
12
+
13
+ ## ุงู„ู…ู…ูŠุฒุงุช ุงู„ุฌุฏูŠุฏุฉ:
14
+ - โœ… ุฃุณู…ุงุก ุงู„ู‡ุฏุงูŠุง ุจุงู„ุนุฑุจูŠ (200+ ู‡ุฏูŠุฉ)
15
+ - โœ… ุตู†ุงุฏูŠู‚ ูˆุญู‚ุงุฆุจ ุงู„ุนู…ู„ุงุช ู…ุน ุงู„ูุงุฆุฒูŠู† (ุงู„ุงุณู… + ุงู„ูŠูˆุฒุฑู†ูŠู… + ุนุฏุฏ ุงู„ุนู…ู„ุงุช)
16
+ - โœ… ุงู„ุชุนู„ูŠู‚ุงุช ู…ุน ุนุฑุถ ุฃุบู„ุจ ุงู„ุฑุณุงุฆู„ ู„ูƒู„ ู…ุนู„ู‚
17
+ - โœ… ุญุฐู ุชู„ู‚ุงุฆูŠ ู„ู„ุฑุณุงุฆู„ ุงู„ุณุงุจู‚ุฉ ุนู†ุฏ ุงู„ุถุบุท ุนู„ู‰ ุฒุฑ ุฌุฏูŠุฏ
18
+ - โœ… ุชู†ุธูŠู ุงู„ุฐุงูƒุฑุฉ ูƒู„ 50 ุฏู‚ูŠู‚ุฉ ู„ู…ู†ุน ุงู„ุซู‚ู„
19
+ - โœ… ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน ู…ู† ุชู„ูŠูƒุฑุงู…: `/change username`
20
+ - โœ… ู‚ู†ุงุฉ ุชู„ูŠูƒุฑุงู… ุซุงู†ูŠุฉ: `/channel2 CHAT_ID`
21
+ - โœ… ุชุตู…ูŠู… ูุฎู… ูˆุงุญุชุฑุงููŠ ู…ุน ุฑุชุจ ุนุฑุจูŠุฉ
22
+
23
+ ## ุงู„ุฃูˆุงู…ุฑ:
24
+ - `/change username` ุฃูˆ `/ุบูŠุฑ username` - ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน ุงู„ู…ุฑุงู‚ุจ
25
+ - `/channel2 CHAT_ID` ุฃูˆ `/ู‚ู†ุงุฉ CHAT_ID` - ุชุนูŠูŠู† ู‚ู†ุงุฉ ุซุงู†ูŠุฉ
26
+ - `/status` ุฃูˆ `/ุญุงู„ุฉ` - ุนุฑุถ ุญุงู„ุฉ ุงู„ุจูˆุช
27
+ - `/clear` ุฃูˆ `/ู…ุณุญ` - ู…ุณุญ ุงู„ุฅุญุตุงุฆูŠุงุช
28
+
29
+ ## ุงู„ู…ุชุบูŠุฑุงุช ุงู„ู…ุทู„ูˆุจุฉ (Secrets):
30
+ - `TIKTOK_USERNAME` - ูŠูˆุฒุฑู†ูŠู… ุงู„ู…ุฐูŠุน
31
+ - `TELEGRAM_TOKEN` - ุชูˆูƒู† ุจูˆุช ุชู„ูŠูƒุฑุงู…
32
+ - `TELEGRAM_CHAT_ID` - ู…ุนุฑู ุงู„ู‚ู†ุงุฉ/ุงู„ุดุงุช
33
+ - `SESSION_ID` - (ุงุฎุชูŠุงุฑูŠ) ุณูŠุดู† ุชูŠูƒ ุชูˆูƒ
34
+ - `SIGN_API_KEY` - (ุงุฎุชูŠุงุฑูŠ) ู…ูุชุงุญ API
35
+ - `TELEGRAM_CHAT_ID_2` - (ุงุฎุชูŠุงุฑูŠ) ู‚ู†ุงุฉ ุซุงู†ูŠุฉ
bot.js ADDED
@@ -0,0 +1,1315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
3
+ * โ•‘ โ•‘
4
+ * โ•‘ ๐ŸŽฏ TikTok Radar Ultimate v11.0 - ุงู„ู†ุณุฎุฉ ุงู„ู…ุญุณู‘ู†ุฉ ๐ŸŽฏ โ•‘
5
+ * โ•‘ โ•‘
6
+ * โ•‘ โœ… ุฃุณู…ุงุก ุงู„ู‡ุฏุงูŠุง ุจุงู„ุนุฑุจูŠ โ€ข ุตู†ุงุฏูŠู‚ ูˆุญู‚ุงุฆุจ ู…ุน ุงู„ูุงุฆุฒูŠู† โ•‘
7
+ * โ•‘ โœ… ุชุนู„ูŠู‚ุงุช ู…ุน ุฃุบู„ุจ ุงู„ุฑุณุงุฆู„ โ€ข ุญุฐู ุชู„ู‚ุงุฆูŠ ู„ู„ุฑุณุงุฆู„ ุงู„ุณุงุจู‚ุฉ โ•‘
8
+ * โ•‘ โœ… ุชุฎุฒูŠู† ูƒู„ 50 ุฏู‚ูŠู‚ุฉ โ€ข ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน ู…ู† ุชู„ูŠูƒุฑุงู… โ€ข ู‚ู†ุงุฉ ุซุงู†ูŠุฉ โ•‘
9
+ * โ•‘ โ•‘
10
+ * โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
11
+ */
12
+
13
+ const http = require('http');
14
+ const axios = require('axios');
15
+
16
+ process.env.WHITELIST_AUTHENTICATED_SESSION_ID_HOST = 'tiktok.eulerstream.com';
17
+ const PORT = process.env.PORT || 7860;
18
+
19
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• CONFIG โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
20
+ const CONFIG = {
21
+ TIKTOK_USERNAME: (process.env.TIKTOK_USERNAME || 'a200_89').trim(),
22
+ SESSION_ID: (process.env.SESSION_ID || '').trim(),
23
+ TT_TARGET_IDC: (process.env.TT_TARGET_IDC || 'alisg').trim(),
24
+ TELEGRAM_TOKEN: (process.env.TELEGRAM_TOKEN || '').trim(),
25
+ TELEGRAM_CHAT_ID: (process.env.TELEGRAM_CHAT_ID || '').trim(),
26
+ TELEGRAM_CHAT_ID_2: (process.env.TELEGRAM_CHAT_ID_2 || '').trim(),
27
+ PROXY_URL: (process.env.PROXY_URL || '').trim().replace(/\/$/, ''),
28
+ SIGN_API_KEY: (process.env.SIGN_API_KEY || '').trim(),
29
+ REPORT_INTERVAL: parseInt(process.env.REPORT_INTERVAL || '10'),
30
+ };
31
+
32
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ุฃุณู…ุงุก ุงู„ู‡ุฏุงูŠุง ุจุงู„ุนุฑุจูŠ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
33
+ const GIFT_NAMES_AR = {
34
+ 'Rose': 'ูˆุฑุฏุฉ ๐ŸŒน', 'rose': 'ูˆุฑุฏุฉ ๐ŸŒน', 'Finger Heart': 'ู‚ู„ุจ ุจุงู„ุฅุตุจุน ๐Ÿคž',
35
+ 'GG': 'ุฌูŠ ุฌูŠ ๐ŸŽฎ', 'Ice Cream Cone': 'ุขูŠุณ ูƒุฑูŠู… ๐Ÿฆ', 'Doughnut': 'ุฏูˆู†ุงุช ๐Ÿฉ',
36
+ 'TikTok': 'ุชูŠูƒ ุชูˆูƒ โ™ช', 'Love you': 'ุฃุญุจูƒ ๐Ÿ’•', 'Confetti': 'ู‚ุตุงุตุงุช ู…ู„ูˆู†ุฉ ๐ŸŽŠ',
37
+ 'Hand Heart': 'ู‚ู„ุจ ุจุงู„ูŠุฏ ๐Ÿ’—', 'Heart Me': 'ู‚ู„ุจู†ูŠ โค๏ธ', 'Tiny Diny': 'ุชุงูŠู†ูŠ ุฏูŠู†ูŠ ๐Ÿฃ',
38
+ 'Cheer You Up': 'ุงุจุชุณู… ๐Ÿ˜Š', 'Sunglasses': 'ู†ุธุงุฑุงุช ุดู…ุณูŠุฉ ๐Ÿ˜Ž', 'Hearts': 'ู‚ู„ูˆุจ ๐Ÿ’•',
39
+ 'Butterfly': 'ูุฑุงุดุฉ ๐Ÿฆ‹', 'Star': 'ู†ุฌู…ุฉ โญ', 'Galaxy': 'ู…ุฌุฑุฉ ๐ŸŒŒ',
40
+ 'Universe': 'ูƒูˆู† ๐ŸŒ', 'Lion': 'ุฃุณุฏ ๐Ÿฆ', 'Interstellar': 'ุจูŠู† ุงู„ู†ุฌูˆู… โœจ',
41
+ 'Concert': 'ุญูู„ุฉ ๐ŸŽต', 'Garland': 'ุฅูƒู„ูŠู„ ๐Ÿ’', 'Superstar': 'ุณูˆุจุฑ ุณุชุงุฑ โญ',
42
+ 'Drama Queen': 'ุฏุฑุงู…ุง ูƒูˆูŠู† ๐Ÿ‘‘', 'Cap': 'ู‚ุจุนุฉ ๐Ÿงข', 'Perfume': 'ุนุทุฑ ๐Ÿ’ซ',
43
+ 'Mic': 'ู…ุงูŠูƒ ๐ŸŽค', 'Paper Crane': 'ุทุงุฆุฑ ูˆุฑู‚ูŠ ๐Ÿฆข', 'Little Crown': 'ุชุงุฌ ุตุบูŠุฑ ๐Ÿ‘‘',
44
+ 'Lollipop': 'ู…ุตุงุตุฉ ๐Ÿญ', 'Lucky Cat': 'ู‚ุทุฉ ุงู„ุญุธ ๐Ÿฑ', 'Love': 'ุญุจ โค๏ธ',
45
+ 'Horseshoe': 'ุญุฏูˆุฉ ุญุตุงู† ๐Ÿด', 'Gift Box': 'ุตู†ุฏูˆู‚ ู‡ุฏูŠุฉ ๐ŸŽ', 'Roses': 'ูˆุฑูˆุฏ ๐ŸŒน',
46
+ 'Bear': 'ุฏุจ ๐Ÿป', 'Teddy Bear': 'ุฏุจุฏูˆุจ ๐Ÿงธ', 'Wish': 'ุฃู…ู†ูŠุฉ ๐ŸŒ ',
47
+ 'Finger': 'ุฅุตุจุน โ˜๏ธ', 'Sending Strength': 'ู‚ูˆุฉ ๐Ÿ’ช', 'Hot Air Balloon': 'ู…ู†ุทุงุฏ ๐ŸŽˆ',
48
+ 'Gold Mine': 'ู…ู†ุฌู… ุฐู‡ุจ โ›๏ธ', 'Thumbs Up': 'ุฅุนุฌุงุจ ๐Ÿ‘', 'Applause': 'ุชุตููŠู‚ ๐Ÿ‘',
49
+ 'Disco Ball': 'ูƒุฑุฉ ุฏูŠุณูƒูˆ ๐Ÿชฉ', 'Money Gun': 'ู…ุณุฏุณ ูู„ูˆุณ ๐Ÿ’ฐ', 'Gem Gun': 'ู…ุณุฏุณ ู…ุงุณุงุช ๐Ÿ’Ž',
50
+ 'Race Car': 'ุณูŠุงุฑุฉ ุณุจุงู‚ ๐ŸŽ๏ธ', 'Sports Car': 'ุณูŠุงุฑุฉ ุฑูŠุงุถูŠุฉ ๐Ÿš—', 'Gaming Chair': 'ูƒุฑุณูŠ ู‚ูŠู…ู†ู‚ ๐Ÿช‘',
51
+ 'Jet': 'ุทุงุฆุฑุฉ โœˆ๏ธ', 'Private Jet': 'ุทุงุฆุฑุฉ ุฎุงุตุฉ โœˆ๏ธ', 'Yacht': 'ูŠุฎุช ๐Ÿ›ฅ๏ธ',
52
+ 'Castle': 'ู‚ู„ุนุฉ ๐Ÿฐ', 'Kingdom': 'ู…ู…ู„ูƒุฉ ๐Ÿ‘‘', 'Crown': 'ุชุงุฌ ๐Ÿ‘‘',
53
+ 'Diamond': 'ู…ุงุณุฉ ๐Ÿ’Ž', 'Lightning Bolt': 'ุตุงุนู‚ุฉ โšก', 'Phoenix': 'ุทุงุฆุฑ ุงู„ููŠู†ูŠู‚ ๐Ÿ”ฅ',
54
+ 'Dragon': 'ุชู†ูŠู† ๐Ÿ‰', 'Elephant': 'ููŠู„ ๐Ÿ˜', 'Corgi': 'ูƒู„ุจ ูƒูˆุฑุฌูŠ ๐Ÿ•',
55
+ 'Duck': 'ุจุทุฉ ๐Ÿฆ†', 'Cat': 'ู‚ุทุฉ ๐Ÿฑ', 'Panda': 'ุจุงู†ุฏุง ๐Ÿผ',
56
+ 'Penguin': 'ุจุทุฑูŠู‚ ๐Ÿง', 'Whale': 'ุญูˆุช ๐Ÿ‹', 'Dolphin': 'ุฏู„ููŠู† ๐Ÿฌ',
57
+ 'Shark': 'ู‚ุฑุด ๐Ÿฆˆ', 'Unicorn': 'ูŠูˆู†ูŠูƒูˆุฑู† ๐Ÿฆ„', 'Pearl Necklace': 'ุนู‚ุฏ ู„ุคู„ุค ๐Ÿ“ฟ',
58
+ 'Ring': 'ุฎุงุชู… ๐Ÿ’', 'Couple Ring': 'ุฎุงุชู… ุฒูˆุฌูŠู† ๐Ÿ’', 'Wedding Ring': 'ุฎุงุชู… ุฒูˆุงุฌ ๐Ÿ’',
59
+ 'Bracelet': 'ุณูˆุงุฑ โŒš', 'Watch': 'ุณุงุน๏ฟฝ๏ฟฝ โŒš', 'Flower': 'ุฒู‡ุฑุฉ ๐ŸŒธ',
60
+ 'Bouquet': 'ุจุงู‚ุฉ ูˆุฑุฏ ๐Ÿ’', 'Cake': 'ูƒูŠูƒุฉ ๐ŸŽ‚', 'Pizza': 'ุจูŠุชุฒุง ๐Ÿ•',
61
+ 'Popcorn': 'ูุดุงุฑ ๐Ÿฟ', 'Coffee': 'ู‚ู‡ูˆุฉ โ˜•', 'Boba Tea': 'ุดุงูŠ ุจูˆุจุง ๐Ÿง‹',
62
+ 'Champagne': 'ุดุงู…ุจุงู†ูŠุง ๐Ÿฅ‚', 'Cocktail': 'ูƒูˆูƒุชูŠู„ ๐Ÿน', 'Fireworks': 'ุฃู„ุนุงุจ ู†ุงุฑูŠุฉ ๐ŸŽ†',
63
+ 'Rocket': 'ุตุงุฑูˆุฎ ๐Ÿš€', 'UFO': 'ุทุจู‚ ุทุงุฆุฑ ๐Ÿ›ธ', 'Moon': 'ู‚ู…ุฑ ๐ŸŒ™',
64
+ 'Sun': 'ุดู…ุณ โ˜€๏ธ', 'Rainbow': 'ู‚ูˆุณ ู‚ุฒุญ ๐ŸŒˆ', 'Snowman': 'ุฑุฌู„ ุซู„ุฌ โ›„',
65
+ 'Cherry Blossom': 'ุฒู‡ุฑ ุงู„ูƒุฑุฒ ๐ŸŒธ', 'Lock & Key': 'ู‚ูู„ ูˆู…ูุชุงุญ ๐Ÿ”',
66
+ 'Money Tree': 'ุดุฌุฑุฉ ูู„ูˆุณ ๐ŸŒณ', 'Lucky Box': 'ุตู†ุฏูˆู‚ ุงู„ุญุธ ๐ŸŽ',
67
+ 'Treasure Chest': 'ุตู†ุฏูˆู‚ ูƒู†ุฒ ๐Ÿ“ฆ', 'Gold Coin': 'ุนู…ู„ุฉ ุฐู‡ุจูŠุฉ ๐Ÿช™',
68
+ 'Coin Bag': 'ุญู‚ูŠุจุฉ ุนู…ู„ุงุช ๐Ÿ’ฐ', 'Scepter': 'ุตูˆู„ุฌุงู† ๐Ÿ†', 'Magic Wand': 'ุนุตุง ุณุญุฑูŠุฉ ๐Ÿช„',
69
+ 'Trophy': 'ูƒุฃุณ ๐Ÿ†', 'Medal': 'ู…ูŠุฏุงู„ูŠุฉ ๐Ÿ…', 'Champion': 'ุจุทู„ ๐Ÿ†',
70
+ 'First Place': 'ุงู„ู…ุฑูƒุฒ ุงู„ุฃูˆู„ ๐Ÿฅ‡', 'Second Place': 'ุงู„ู…ุฑูƒุฒ ุงู„ุซุงู†ูŠ ๐Ÿฅˆ',
71
+ 'Third Place': 'ุงู„ู…ุฑูƒุฒ ุงู„ุซุงู„ุซ ๐Ÿฅ‰', 'Goat': 'ุงู„ุฃูุถู„ ๐Ÿ',
72
+ 'Guitar': 'ุฌูŠุชุงุฑ ๐ŸŽธ', 'Piano': 'ุจูŠุงู†ูˆ ๐ŸŽน', 'Drum': 'ุทุจู„ ๐Ÿฅ',
73
+ 'Headphones': 'ุณู…ุงุนุงุช ๐ŸŽง', 'Microphone': 'ู…ุงูŠูƒุฑูˆููˆู† ๐ŸŽค',
74
+ 'Camera': 'ูƒุงู…ูŠุฑุง ๐Ÿ“ท', 'Movie': 'ูู„ู… ๐ŸŽฌ', 'Ticket': 'ุชุฐูƒุฑุฉ ๐ŸŽŸ๏ธ',
75
+ 'Balloon': 'ุจุงู„ูˆู† ๐ŸŽˆ', 'Party': 'ุญูู„ุฉ ๐Ÿฅณ', 'Birthday': 'ุนูŠุฏ ู…ูŠู„ุงุฏ ๐ŸŽ‚',
76
+ 'Graduation': 'ุชุฎุฑุฌ ๐ŸŽ“', 'Coin': 'ุนู…ู„ุฉ ๐Ÿช™', 'Money Bag': 'ูƒูŠุณ ู†ู‚ูˆุฏ ๐Ÿ’ฐ',
77
+ 'Dollar': 'ุฏูˆู„ุงุฑ ๐Ÿ’ต', 'Credit Card': 'ุจุทุงู‚ุฉ ๐Ÿ’ณ', 'Gem Stone': 'ุญุฌุฑ ูƒุฑูŠู… ๐Ÿ’Ž',
78
+ 'Pearl': 'ู„ุคู„ุคุฉ ๐Ÿซง', 'Leaf': 'ูˆุฑู‚ุฉ ุดุฌุฑ ๐Ÿƒ', 'Clover': 'ุจุฑุณูŠู… ๐Ÿ€',
79
+ 'Sunflower': 'ุนุจุงุฏ ุงู„ุดู…ุณ ๐ŸŒป', 'Lotus': 'ู„ูˆุชุณ ๐Ÿชท', 'Hug': 'ุญุถู† ๐Ÿค—',
80
+ 'Kiss': 'ู‚ุจู„ุฉ ๐Ÿ’‹', 'Clap': 'ุชุตููŠู‚ ๐Ÿ‘', 'Pray': 'ุฏุนุงุก ๐Ÿ™',
81
+ 'Flex': 'ุนุถู„ุงุช ๐Ÿ’ช', 'Peace': 'ุณู„ุงู… โœŒ๏ธ', 'OK': 'ุฃูˆูƒูŠ ๐Ÿ‘Œ',
82
+ 'Fist': 'ู‚ุจุถุฉ ๐Ÿ‘Š', 'Handshake': 'ู…ุตุงูุญุฉ ๐Ÿค', 'Heart Eyes': 'ุนูŠูˆู† ู‚ู„ุจ ๐Ÿ˜',
83
+ };
84
+
85
+ function getArabicGiftName(en) {
86
+ if (!en) return 'ู‡ุฏูŠุฉ ๐ŸŽ';
87
+ if (GIFT_NAMES_AR[en]) return GIFT_NAMES_AR[en];
88
+ const lower = en.toLowerCase();
89
+ for (const [k, v] of Object.entries(GIFT_NAMES_AR)) {
90
+ if (k.toLowerCase() === lower) return v;
91
+ if (lower.includes(k.toLowerCase()) || k.toLowerCase().includes(lower)) return v;
92
+ }
93
+ return `${en} ๐ŸŽ`;
94
+ }
95
+
96
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• STATE โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
97
+ let isConnected = false, tiktokConnection = null;
98
+ let totalGifts = 0, totalDiamonds = 0, totalLikes = 0, totalComments = 0;
99
+ let totalFollows = 0, totalShares = 0, totalSuperFans = 0, totalQuestions = 0;
100
+ let totalEnvelopes = 0, totalEmotes = 0;
101
+ let maxViewers = 0, currentViewers = 0;
102
+ let startTime = null;
103
+
104
+ // Maps - ุงู„ุขู† ู…ุน ุชุฎุฒูŠู† ุงู„ุฑุณุงุฆู„ ูˆุงู„ู‡ุฏุงูŠุง
105
+ let giftersMap = {}; // { uid: { name, username, coins, count, gifts: [] } }
106
+ let followersMap = {}; // { uid: { name, username, time } }
107
+ let chattersMap = {}; // { uid: { name, username, count, messages: [] } }
108
+ let sharersMap = {}; // { uid: { name, username, count } }
109
+ let likersMap = {}; // { uid: { name, username, count } }
110
+
111
+ // ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ ู…ุน ุงู„ูุงุฆุฒูŠู†
112
+ let envelopeWinners = []; // { type, sender, senderUsername, diamonds, peopleCount, winners: [{name, username, coins}], time }
113
+
114
+ let questionsArr = [], pinnedMessages = [];
115
+ let reconnectTimer = null, reportInterval = null, flushInterval = null;
116
+ let roomTitle = '';
117
+
118
+ // ุฑุณุงุฆู„ ู…ุฑุณู„ุฉ ู„ู„ุญุฐู
119
+ let lastMenuMsgId = null;
120
+ let lastReportMsgId = null;
121
+ let lastDetailMsgIds = [];
122
+
123
+ // PK
124
+ let pkActive = false, pkInfo = {
125
+ battleId: '', participantDetails: [], ourScore: 0, theirScore: 0,
126
+ startTime: null, pkGifts: {},
127
+ };
128
+
129
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• UTILS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
130
+ function esc(t) { return t ? String(t).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') : ''; }
131
+ function formatK(n) { n = Number(n) || 0; return n >= 1e6 ? (n / 1e6).toFixed(1) + 'M' : n >= 1e3 ? (n / 1e3).toFixed(1) + 'K' : n.toString(); }
132
+ function dur(s) { if (!s) return '00:00:00'; const d = Math.floor((Date.now() - s.getTime()) / 1000); return `${String(Math.floor(d / 3600)).padStart(2, '0')}:${String(Math.floor((d % 3600) / 60)).padStart(2, '0')}:${String(d % 60).padStart(2, '0')}`; }
133
+ function getTime() { return new Date().toLocaleString('ar-IQ', { timeZone: 'Asia/Baghdad', hour: '2-digit', minute: '2-digit', hour12: true }); }
134
+ function getDate() { return new Date().toLocaleString('ar-IQ', { timeZone: 'Asia/Baghdad', year: 'numeric', month: '2-digit', day: '2-digit' }); }
135
+ const LIVE = () => `https://www.tiktok.com/@${CONFIG.TIKTOK_USERNAME}/live`;
136
+
137
+ const medals = ['๐Ÿฅ‡', '๐Ÿฅˆ', '๐Ÿฅ‰', '๐Ÿ…', '๐ŸŽ–๏ธ', 'โญ', 'โœจ', '๐Ÿ’ซ', '๐ŸŒŸ', 'โšก'];
138
+ const ranks = ['ุงู„ุฃูˆู„', 'ุงู„ุซุงู†ูŠ', 'ุงู„ุซุงู„ุซ', 'ุงู„ุฑุงุจุน', 'ุงู„ุฎุงู…ุณ', 'ุงู„ุณุงุฏุณ', 'ุงู„ุณุงุจุน', 'ุงู„ุซุงู…ู†', 'ุงู„ุชุงุณุน', 'ุงู„ุนุงุดุฑ'];
139
+
140
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ENVELOPE HELPERS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
141
+ function extractWinners(data) {
142
+ const winners = [];
143
+ if (!data) return winners;
144
+
145
+ // ุงู„ุจุญุซ ููŠ ูƒู„ ุงู„ู…ูˆุงู‚ุน ุงู„ู…ู…ูƒู†ุฉ ู„ู„ูุงุฆุฒูŠู†
146
+ const possibleLists = [
147
+ data.envelopeGrabUserList,
148
+ data.grabUserList,
149
+ data.winnerList,
150
+ data.winners,
151
+ data.envelopeGrabRecordList,
152
+ data.grabRecordList,
153
+ data.userList,
154
+ data.envelopeInfo?.envelopeGrabUserList,
155
+ data.envelopeInfo?.grabUserList,
156
+ data.envelopeInfo?.winners,
157
+ data.treasureBoxData?.winners,
158
+ data.goodyBagData?.winners,
159
+ ];
160
+
161
+ for (const list of possibleLists) {
162
+ if (Array.isArray(list) && list.length > 0) {
163
+ for (const w of list) {
164
+ if (w) {
165
+ winners.push({
166
+ name: w.nickname || w.nickName || w.userName || w.name || w.uniqueId || w.unique_id || '?',
167
+ username: w.uniqueId || w.unique_id || w.userId || '',
168
+ coins: w.diamondCount || w.coinCount || w.coins || w.grabDiamond || w.amount || w.value || 0,
169
+ });
170
+ }
171
+ }
172
+ break; // ุชูˆู‚ู ุนู†ุฏ ุฅูŠุฌุงุฏ ู‚ุงุฆู…ุฉ
173
+ }
174
+ }
175
+
176
+ return winners;
177
+ }
178
+
179
+ function updateLastEnvelopeWithWinners(winners) {
180
+ if (winners.length === 0) return;
181
+
182
+ console.log(`[๐Ÿ“ฆ WINNERS FOUND!] ${winners.length} winners:`, winners.map(w => `${w.name}(${w.coins})`).join(', '));
183
+
184
+ // ุชุญุฏูŠุซ ุขุฎุฑ ุตู†ุฏูˆู‚ ุจุงู„ูุงุฆุฒูŠู†
185
+ if (envelopeWinners.length > 0) {
186
+ const lastEnv = envelopeWinners[envelopeWinners.length - 1];
187
+ // ูู‚ุท ุฅุฐุง ู„ู… ูŠูƒู† ู„ุฏูŠู‡ ูุงุฆุฒูŠู† ุจุงู„ูุนู„
188
+ if (!lastEnv.winners || lastEnv.winners.length === 0) {
189
+ lastEnv.winners = winners;
190
+
191
+ // ุฅุฑุณุงู„ ุชุญุฏูŠุซ ุจุงู„ูุงุฆุฒูŠู†
192
+ const typeIcon = lastEnv.type === 'coinbag' ? '๐Ÿ’ฐ' : '๐Ÿ“ฆ';
193
+ const typeName = lastEnv.type === 'coinbag' ? 'ุญู‚ูŠุจุฉ ุงู„ุนู…ู„ุงุช' : 'ุตู†ุฏูˆู‚ ุงู„ูƒู†ุฒ';
194
+
195
+ const winnerText = winners.map((w, i) =>
196
+ ` ${i + 1}. ๐Ÿ‘ค <b>${esc(w.name)}</b> ${w.username ? `<code>@${w.username}</code>` : ''}\n ๐Ÿช™ ุญุตู„ ุนู„ู‰: <b>${formatK(w.coins)}</b> ุนู…ู„ุฉ`
197
+ ).join('\n');
198
+
199
+ sendBoth(
200
+ `๐Ÿ†โœจ <b>ูุงุฆุฒูŠู† ${typeName}!</b>\n` +
201
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
202
+ `๐Ÿ‘ค ุงู„ู…ุฑุณู„: <b>${esc(lastEnv.sender)}</b>\n\n` +
203
+ winnerText
204
+ );
205
+ }
206
+ }
207
+ }
208
+
209
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• FORMATTERS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
210
+ function fmtList(map, sortKey, emoji, unit, n = 10) {
211
+ const items = Object.values(map).sort((a, b) => (b[sortKey] || 0) - (a[sortKey] || 0)).slice(0, n);
212
+ if (!items.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุจูŠุงู†ุงุช ุจุนุฏ';
213
+ return items.map((x, i) => {
214
+ const m = medals[i] || `${i + 1}.`;
215
+ const rank = ranks[i] || `#${i + 1}`;
216
+ const u = x.username ? `\n โ”— <code>@${x.username}</code>` : '';
217
+ const val = formatK(x[sortKey] || 0);
218
+ return `${m} <b>ุงู„ู…ุฑูƒุฒ ${rank}</b>\n โ”œ ๐Ÿ‘ค <b>${esc(x.name)}</b>: ${val} ${unit}${u}`;
219
+ }).join('\n\n');
220
+ }
221
+
222
+ // ุชู†ุณูŠู‚ ุงู„ู…ุนู„ู‚ูŠู† ู…ุน ุนุฑุถ ุชุนู„ูŠู‚ุงุชู‡ู…
223
+ function fmtChatters(n = 10) {
224
+ const items = Object.values(chattersMap).sort((a, b) => (b.count || 0) - (a.count || 0)).slice(0, n);
225
+ if (!items.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุจูŠุงู†ุงุช ุจุนุฏ';
226
+ return items.map((x, i) => {
227
+ const m = medals[i] || `${i + 1}.`;
228
+ const rank = ranks[i] || `#${i + 1}`;
229
+ const u = x.username ? `\n โ”— <code>@${x.username}</code>` : '';
230
+ const lastMsgs = (x.messages || []).slice(-3).map(msg => ` ๐Ÿ’ฌ <i>"${esc(msg.substring(0, 50))}${msg.length > 50 ? '...' : ''}"</i>`).join('\n');
231
+ return `${m} <b>ุงู„ู…ุฑูƒุฒ ${rank}</b>\n โ”œ ๐Ÿ‘ค <b>${esc(x.name)}</b>: ${x.count} ุชุนู„ูŠู‚${u}\n${lastMsgs || ' ๐Ÿ’ฌ <i>ู„ุง ุชุนู„ูŠู‚ุงุช ู…ุญููˆุธุฉ</i>'}`;
232
+ }).join('\n\n');
233
+ }
234
+
235
+ // ุชู†ุณูŠู‚ ุงู„ู‡ุฏุงูŠุง ู…ุน ุฃุณู…ุงุก ุนุฑุจูŠุฉ
236
+ function fmtGifters(n = 10) {
237
+ const items = Object.values(giftersMap).sort((a, b) => (b.coins || 0) - (a.coins || 0)).slice(0, n);
238
+ if (!items.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุจูŠุงู†ุงุช ุจุนุฏ';
239
+ return items.map((x, i) => {
240
+ const m = medals[i] || `${i + 1}.`;
241
+ const rank = ranks[i] || `#${i + 1}`;
242
+ const u = x.username ? `\n โ”— <code>@${x.username}</code>` : '';
243
+ const giftNames = (x.gifts || []).slice(-3).map(g => getArabicGiftName(g)).join(' โ€ข ');
244
+ return `${m} <b>ุงู„ู…ุฑูƒุฒ ${rank}</b>\n โ”œ ๐Ÿ‘ค <b>${esc(x.name)}</b>: ${formatK(x.coins)} ๐Ÿ’Ž (${x.count} ู‡ุฏูŠุฉ)${u}\n โ”” ุขุฎุฑ ุงู„ู‡ุฏุงูŠุง: ${giftNames || 'ุบูŠุฑ ู…ุญุฏุฏ'}`;
245
+ }).join('\n\n');
246
+ }
247
+
248
+ // ุชู†ุณูŠู‚ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ
249
+ function fmtEnvelopes(n = 10) {
250
+ if (!envelopeWinners.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุตู†ุงุฏูŠู‚ ุฃูˆ ุญู‚ุงุฆุจ ุจุนุฏ';
251
+ return envelopeWinners.slice(-n).reverse().map((env, i) => {
252
+ const typeIcon = env.type === 'coinbag' ? '๐Ÿ’ฐ' : '๐Ÿ“ฆ';
253
+ const typeName = env.type === 'coinbag' ? 'ุญู‚ูŠุจุฉ ุนู…ู„ุงุช' : 'ุตู†ุฏูˆู‚ ูƒู†ุฒ';
254
+ const winList = (env.winners || []).map((w, wi) =>
255
+ ` ${wi + 1}. ๐Ÿ‘ค <b>${esc(w.name)}</b> ${w.username ? `<code>@${w.username}</code>` : ''} โ†’ ๐Ÿช™ ${formatK(w.coins)} ุนู…ู„ุฉ`
256
+ ).join('\n') || ' โณ ู„ู… ูŠุธู‡ุฑ ุงู„ูุงุฆุฒูŠู† ุจุนุฏ';
257
+ return `${typeIcon} <b>${typeName}</b> #${envelopeWinners.length - i}\n โ”œ ุงู„ู…ุฑุณู„: <b>${esc(env.sender)}</b> ${env.senderUsername ? `<code>@${env.senderUsername}</code>` : ''}\n โ”œ ๐Ÿ’Ž ${formatK(env.diamonds)} ู…ุงุณุฉ โ€ข ๐Ÿ‘ฅ ${env.peopleCount || '?'} ุดุฎุต\n โ”” ๐Ÿ† ุงู„ูุงุฆุฒูŠู†:\n${winList}`;
258
+ }).join('\n\n');
259
+ }
260
+
261
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• TELEGRAM โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
262
+ async function sendTg(text, silent = false, buttons = null, chatId = null) {
263
+ const targetChatId = chatId || CONFIG.TELEGRAM_CHAT_ID;
264
+ if (!CONFIG.TELEGRAM_TOKEN || !targetChatId) return null;
265
+ const urls = [];
266
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
267
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
268
+ for (const base of urls) {
269
+ try {
270
+ const p = { chat_id: targetChatId, text, parse_mode: 'HTML', disable_notification: silent, disable_web_page_preview: true };
271
+ if (buttons) p.reply_markup = { inline_keyboard: buttons };
272
+ const r = await axios.post(`${base}/sendMessage`, p, { timeout: 15000 });
273
+ if (r.data?.ok) return r.data;
274
+ } catch (e) {}
275
+ }
276
+ return null;
277
+ }
278
+
279
+ async function deleteTgMsg(chatId, msgId) {
280
+ if (!CONFIG.TELEGRAM_TOKEN || !chatId || !msgId) return;
281
+ const urls = [];
282
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
283
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
284
+ for (const base of urls) {
285
+ try {
286
+ await axios.post(`${base}/deleteMessage`, { chat_id: chatId, message_id: msgId }, { timeout: 10000 });
287
+ return;
288
+ } catch (e) {}
289
+ }
290
+ }
291
+
292
+ async function answerCallback(callbackId, text = '') {
293
+ const urls = [];
294
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
295
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
296
+ for (const base of urls) {
297
+ try {
298
+ await axios.post(`${base}/answerCallbackQuery`, { callback_query_id: callbackId, text, show_alert: !!text }, { timeout: 10000 });
299
+ return;
300
+ } catch (e) {}
301
+ }
302
+ }
303
+
304
+ // ุฅุฑุณุงู„ ู„ู„ู‚ู†ุงุชูŠู†
305
+ async function sendBoth(text, silent = false, buttons = null) {
306
+ const result = await sendTg(text, silent, buttons);
307
+ if (CONFIG.TELEGRAM_CHAT_ID_2) {
308
+ sendTg(text, silent, buttons, CONFIG.TELEGRAM_CHAT_ID_2).catch(() => {});
309
+ }
310
+ return result;
311
+ }
312
+
313
+ // ุฅุฑุณุงู„ ู…ุน ุญุฐู ุงู„ุณุงุจู‚
314
+ async function sendAndReplace(text, silent, buttons, type) {
315
+ // ุญุฐู ุงู„ุฑุณุงู„ุฉ ุงู„ุณุงุจู‚ุฉ ู…ู† ู†ูุณ ุงู„ู†ูˆุน
316
+ if (type === 'menu' && lastMenuMsgId) {
317
+ await deleteTgMsg(CONFIG.TELEGRAM_CHAT_ID, lastMenuMsgId);
318
+ lastMenuMsgId = null;
319
+ } else if (type === 'report' && lastReportMsgId) {
320
+ await deleteTgMsg(CONFIG.TELEGRAM_CHAT_ID, lastReportMsgId);
321
+ lastReportMsgId = null;
322
+ } else if (type === 'detail') {
323
+ for (const mid of lastDetailMsgIds) {
324
+ await deleteTgMsg(CONFIG.TELEGRAM_CHAT_ID, mid);
325
+ }
326
+ lastDetailMsgIds = [];
327
+ }
328
+
329
+ const result = await sendTg(text, silent, buttons);
330
+ if (result?.result?.message_id) {
331
+ if (type === 'menu') lastMenuMsgId = result.result.message_id;
332
+ else if (type === 'report') lastReportMsgId = result.result.message_id;
333
+ else if (type === 'detail') lastDetailMsgIds.push(result.result.message_id);
334
+ }
335
+
336
+ // ุฅุฑุณุงู„ ู„ู„ู‚ู†ุงุฉ ุงู„ุซุงู†ูŠุฉ
337
+ if (CONFIG.TELEGRAM_CHAT_ID_2) {
338
+ sendTg(text, silent, buttons, CONFIG.TELEGRAM_CHAT_ID_2).catch(() => {});
339
+ }
340
+ return result;
341
+ }
342
+
343
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• TEXT COMMANDS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
344
+ async function handleTextCommand(msg) {
345
+ const text = (msg.text || '').trim();
346
+ const chatId = String(msg.chat?.id || '');
347
+
348
+ // ูู‚ุท ุงู„ู…ุดุฑู
349
+ if (chatId !== CONFIG.TELEGRAM_CHAT_ID) return;
350
+
351
+ // ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน: /change username ุฃูˆ /ุบูŠุฑ username
352
+ if (text.startsWith('/change') || text.startsWith('/ุบูŠุฑ')) {
353
+ const parts = text.split(/\s+/);
354
+ const newUser = parts[1]?.replace('@', '').trim();
355
+ if (newUser) {
356
+ const oldUser = CONFIG.TIKTOK_USERNAME;
357
+ CONFIG.TIKTOK_USERNAME = newUser;
358
+
359
+ // ูุตู„ ุงู„ุงุชุตุงู„ ุงู„ุญุงู„ูŠ
360
+ if (tiktokConnection) {
361
+ try { tiktokConnection.disconnect(); } catch (e) {}
362
+ }
363
+ isConnected = false;
364
+
365
+ await sendTg(
366
+ `๐Ÿ”„ <b>ุชู… ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน!</b>\n` +
367
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
368
+ `โŒ ุงู„ุณุงุจู‚: <code>@${oldUser}</code>\n` +
369
+ `โœ… ุงู„ุฌุฏูŠุฏ: <code>@${newUser}</code>\n\n` +
370
+ `โณ ุฌุงุฑูŠ ุงู„ุงุชุตุงู„ ุจุงู„ุจุซ ุงู„ุฌุฏูŠุฏ...`
371
+ );
372
+
373
+ setTimeout(startBot, 3000);
374
+ } else {
375
+ await sendTg(`โŒ ุงุณุชุฎุฏู…: <code>/change username</code>\nุฃูˆ: <code>/ุบูŠุฑ username</code>`);
376
+ }
377
+ return;
378
+ }
379
+
380
+ // ุชุนูŠูŠู† ู‚ู†ุงุฉ ุซุงู†ูŠุฉ: /channel2 CHAT_ID ุฃูˆ /ู‚ู†ุงุฉ CHAT_ID
381
+ if (text.startsWith('/channel2') || text.startsWith('/ู‚ู†ุงุฉ')) {
382
+ const parts = text.split(/\s+/);
383
+ const newChannelId = parts[1]?.trim();
384
+ if (newChannelId) {
385
+ CONFIG.TELEGRAM_CHAT_ID_2 = newChannelId;
386
+ await sendTg(
387
+ `๐Ÿ“ข <b>ุชู… ุชุนูŠูŠู† ุงู„ู‚ู†ุงุฉ ุงู„ุซุงู†ูŠุฉ!</b>\n` +
388
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
389
+ `โœ… ู…ุนุฑู ุงู„ู‚ู†ุงุฉ: <code>${newChannelId}</code>\n` +
390
+ `๐Ÿ“ค ุณูŠุชู… ุฅุฑุณุงู„ ุฌู…ูŠุน ุงู„ุชู‚ุงุฑูŠุฑ ู„ู‡ุฐู‡ ุงู„ู‚ู†ุงุฉ ุฃูŠุถุงู‹`
391
+ );
392
+ } else {
393
+ await sendTg(`โŒ ุงุณุชุฎุฏู…: <code>/channel2 CHAT_ID</code>\nุฃูˆ: <code>/ู‚ู†ุงุฉ CHAT_ID</code>`);
394
+ }
395
+ return;
396
+ }
397
+
398
+ // ุงู„ุญุงู„ุฉ: /status ุฃูˆ /ุญุงู„ุฉ
399
+ if (text === '/status' || text === '/ุญุงู„ุฉ') {
400
+ await sendTg(
401
+ `๐Ÿ“ก <b>ุญุงู„ุฉ ุงู„ุจูˆุช</b>\n` +
402
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
403
+ `๐Ÿ‘ค ุงู„ู…ุฐูŠุน: <code>@${CONFIG.TIKTOK_USERNAME}</code>\n` +
404
+ `${isConnected ? '๐ŸŸข ู…ุชุตู„' : '๐Ÿ”ด ุบูŠุฑ ู…ุชุตู„'}\n` +
405
+ `โฑ ุงู„ู…ุฏุฉ: ${dur(startTime)}\n` +
406
+ `๐Ÿ“ข ุงู„ู‚ู†ุงุฉ ุงู„ุซุงู†ูŠุฉ: ${CONFIG.TELEGRAM_CHAT_ID_2 ? `<code>${CONFIG.TELEGRAM_CHAT_ID_2}</code>` : 'ุบูŠุฑ ู…ุนูŠู‘ู†ุฉ'}\n\n` +
407
+ `<b>ุงู„ุฃูˆุงู…ุฑ ุงู„ู…ุชุงุญุฉ:</b>\n` +
408
+ `โ€ข <code>/change username</code> - ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน\n` +
409
+ `โ€ข <code>/channel2 CHAT_ID</code> - ุชุนูŠูŠู† ู‚ู†ุงุฉ ุซุงู†ูŠุฉ\n` +
410
+ `โ€ข <code>/status</code> - ุญุงู„ุฉ ุงู„ุจูˆุช\n` +
411
+ `โ€ข <code>/clear</code> - ู…ุณุญ ุงู„ุฅุญุตุงุฆูŠุงุช`
412
+ );
413
+ return;
414
+ }
415
+
416
+ // ู…ุณุญ ุงู„ุฅุญุตุงุฆูŠุงุช: /clear ุฃูˆ /ู…ุณุญ
417
+ if (text === '/clear' || text === '/ู…ุณุญ') {
418
+ clearStats();
419
+ await sendTg(`โœ… ุชู… ู…ุณุญ ุฌู…ูŠุน ุงู„ุฅุญุตุงุฆูŠุงุช`);
420
+ return;
421
+ }
422
+ }
423
+
424
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• CALLBACK HANDLER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
425
+ async function handleCallback(data) {
426
+ const cb = data.data;
427
+ const cbId = data.id;
428
+
429
+ switch (cb) {
430
+ case 'gifts':
431
+ await sendAndReplace(
432
+ `๐ŸŽ <b>โ”โ”โ”โ” ู„ูˆุญุฉ ุงู„ู‡ุฏุงูŠุง โ”โ”โ”โ”</b>\n` +
433
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
434
+ `๐Ÿ’Ž ุฅุฌู…ุงู„ูŠ ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` +
435
+ `๐ŸŽ ุนุฏุฏ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n\n` +
436
+ `โ”โ”โ” ๐Ÿ† ุชุฑุชูŠุจ ุงู„ุฏุงุนู…ูŠู† โ”โ”โ”\n\n${fmtGifters(10)}`,
437
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
438
+ );
439
+ break;
440
+
441
+ case 'followers':
442
+ await sendAndReplace(
443
+ `โž• <b>โ”โ”โ”โ” ุงู„ู…ุชุงุจุนูŠู† ุงู„ุฌุฏุฏ โ”โ”โ”โ”</b>\n` +
444
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
445
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${totalFollows}</b> ู…ุชุงุจุน ุฌุฏูŠุฏ\n\n` +
446
+ `โ”โ”โ” ๐Ÿ‘ฅ ุขุฎุฑ ุงู„ู…ุชุงุจุนูŠู† โ”โ”โ”\n\n${fmtList(followersMap, 'time', 'โž•', '')}`,
447
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
448
+ );
449
+ break;
450
+
451
+ case 'likes':
452
+ await sendAndReplace(
453
+ `โค๏ธ <b>โ”โ”โ”โ” ุงู„ุฅุนุฌุงุจุงุช โ”โ”โ”โ”</b>\n` +
454
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
455
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${formatK(totalLikes)}</b> ุฅุนุฌุงุจ\n\n` +
456
+ `โ”โ”โ” ๐Ÿ”ฅ ุฃูƒุซุฑ ุงู„ู…ุนุฌุจูŠู† โ”โ”โ”\n\n${fmtList(likersMap, 'count', 'โค๏ธ', 'โค๏ธ')}`,
457
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
458
+ );
459
+ break;
460
+
461
+ case 'chatters':
462
+ await sendAndReplace(
463
+ `๐Ÿ’ฌ <b>โ”โ”โ”โ” ุงู„ุชุนู„ูŠู‚ุงุช โ”โ”โ”โ”</b>\n` +
464
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
465
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${formatK(totalComments)}</b> ุชุนู„ูŠู‚\n\n` +
466
+ `โ”โ”โ” ๐Ÿ—ฃ๏ธ ุฃู†ุดุท ุงู„ู…ุนู„ู‚ูŠู† โ”โ”โ”\n\n${fmtChatters(10)}`,
467
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
468
+ );
469
+ break;
470
+
471
+ case 'shares':
472
+ await sendAndReplace(
473
+ `โ†ช๏ธ <b>โ”โ”โ”โ” ุงู„ู…ุดุงุฑูƒุงุช โ”โ”โ”โ”</b>\n` +
474
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
475
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${totalShares}</b> ู…ุดุงุฑูƒุฉ\n\n` +
476
+ `โ”โ”โ” ๐Ÿ”„ ุฃูƒุซุฑ ุงู„ู…ุดุงุฑูƒูŠู† โ”โ”โ”\n\n${fmtList(sharersMap, 'count', 'โ†ช๏ธ', 'โ†ช๏ธ')}`,
477
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
478
+ );
479
+ break;
480
+
481
+ case 'envelopes':
482
+ await sendAndReplace(
483
+ `๐Ÿ“ฆ๐Ÿ’ฐ <b>โ”โ”โ”โ” ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ โ”โ”โ”โ”</b>\n` +
484
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
485
+ `๐Ÿ“ฆ ุฅุฌู…ุงู„ูŠ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n\n` +
486
+ `โ”โ”โ” ๐Ÿ† ุขุฎุฑ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ โ”โ”โ”\n\n${fmtEnvelopes(10)}`,
487
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
488
+ );
489
+ break;
490
+
491
+ case 'questions':
492
+ const qList = questionsArr.slice(-10).reverse().map((q, i) =>
493
+ `${i + 1}. <b>${esc(q.name)}</b>\n โ“ <i>"${esc(q.text)}"</i>`
494
+ ).join('\n\n') || ' ู„ุง ูŠูˆุฌุฏ ุฃุณุฆู„ุฉ';
495
+ await sendAndReplace(
496
+ `โ“ <b>โ”โ”โ”โ” ุงู„ุฃุณุฆู„ุฉ โ”โ”โ”โ”</b>\n` +
497
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
498
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${totalQuestions}</b> ุณุคุงู„\n\n${qList}`,
499
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
500
+ );
501
+ break;
502
+
503
+ case 'top_active':
504
+ const activeMap = {};
505
+ for (const [uid, g] of Object.entries(giftersMap)) {
506
+ if (!activeMap[uid]) activeMap[uid] = { name: g.name, username: g.username, score: 0 };
507
+ activeMap[uid].score += (g.coins || 0);
508
+ }
509
+ for (const [uid, c] of Object.entries(chattersMap)) {
510
+ if (!activeMap[uid]) activeMap[uid] = { name: c.name, username: c.username, score: 0 };
511
+ activeMap[uid].score += (c.count || 0) * 5;
512
+ }
513
+ for (const [uid, l] of Object.entries(likersMap)) {
514
+ if (!activeMap[uid]) activeMap[uid] = { name: l.name, username: l.username, score: 0 };
515
+ activeMap[uid].score += (l.count || 0);
516
+ }
517
+ for (const [uid, s] of Object.entries(sharersMap)) {
518
+ if (!activeMap[uid]) activeMap[uid] = { name: s.name, username: s.username, score: 0 };
519
+ activeMap[uid].score += (s.count || 0) * 20;
520
+ }
521
+ await sendAndReplace(
522
+ `๐Ÿ‘‘ <b>โ”โ”โ”โ” ุฃูƒุซุฑ ุงู„ู…ุชูุงุนู„ูŠู† โ”โ”โ”โ”</b>\n` +
523
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
524
+ `<i>๐Ÿงฎ ุงู„ู†ู‚ุงุท = ู…ุงุณุงุช + (ุชุนู„ูŠู‚ุงุชร—5) + (ู„ุงูŠูƒุงุช) + (ู…ุดุงุฑูƒุงุชร—20)</i>\n\n` +
525
+ `${fmtList(activeMap, 'score', '๐Ÿ‘‘', 'ู†ู‚ุทุฉ')}`,
526
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
527
+ );
528
+ break;
529
+
530
+ case 'stats':
531
+ const avgV = maxViewers > 0 ? Math.round((currentViewers + maxViewers) / 2) : currentViewers;
532
+ await sendAndReplace(
533
+ `๐Ÿ“ˆ <b>โ”โ”โ”โ” ุฅุญุตุงุฆูŠุงุช ู…ูุตู„ุฉ โ”โ”โ”โ”</b>\n` +
534
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
535
+ `โฑ ุงู„ู…ุฏุฉ: <b>${dur(startTime)}</b>\n` +
536
+ `๐Ÿ“… ${getDate()}\n\n` +
537
+ `โ”โ”โ” ๐Ÿ‘ ุงู„ู…ุดุงู‡ุฏูŠู† โ”โ”โ”\n` +
538
+ `ุงู„ุญุงู„ูŠูŠู†: <b>${formatK(currentViewers)}</b>\n` +
539
+ `ุงู„ุฃุนู„ู‰: <b>${formatK(maxViewers)}</b>\n` +
540
+ `ุงู„ู…ุชูˆุณุท: ~<b>${formatK(avgV)}</b>\n\n` +
541
+ `โ”โ”โ” ๐Ÿ“Š ุงู„ุฃุฑู‚ุงู… โ”โ”โ”\n` +
542
+ `๐Ÿ’Ž ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` +
543
+ `๐ŸŽ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n` +
544
+ `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n` +
545
+ `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช: <b>${totalComments}</b>\n` +
546
+ `โž• ุงู„ู…ุชุงุจุนูŠู†: <b>${totalFollows}</b>\n` +
547
+ `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช: <b>${totalShares}</b>\n` +
548
+ `โญ ุณูˆุจุฑ ูุงู†: <b>${totalSuperFans}</b>\n` +
549
+ `๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n` +
550
+ `โ“ ุงู„ุฃุณุฆู„ุฉ: <b>${totalQuestions}</b>\n` +
551
+ `๐Ÿ˜€ ุงู„ุฅูŠู…ูˆุช: <b>${totalEmotes}</b>`,
552
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
553
+ );
554
+ break;
555
+
556
+ case 'pk_status':
557
+ if (pkActive) {
558
+ const pkG = Object.values(pkInfo.pkGifts).sort((a, b) => b.coins - a.coins).slice(0, 5)
559
+ .map((g, i) => `${medals[i]} <b>${esc(g.name)}</b>: ${formatK(g.coins)} ๐Ÿ’Ž`).join('\n') || 'ู„ุง ูŠูˆุฌุฏ';
560
+ await sendAndReplace(
561
+ `โš”๏ธ <b>โ”โ”โ”โ” ุญุงู„ุฉ PK โ”โ”โ”โ”</b>\n` +
562
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
563
+ `๐Ÿ’Ž ุงู„ู†ุชูŠุฌุฉ: <b>${formatK(pkInfo.ourScore)}</b>\n` +
564
+ `โฑ ุงู„ู…ุฏุฉ: ${dur(pkInfo.startTime)}\n\n` +
565
+ `๐Ÿ† ุงู„ุฏุงุนู…ูŠู†:\n${pkG}`,
566
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
567
+ );
568
+ } else {
569
+ await answerCallback(cbId, 'โš”๏ธ ู„ุง ูŠูˆุฌุฏ ุฌูˆู„ุฉ PK ู†ุดุทุฉ');
570
+ return;
571
+ }
572
+ break;
573
+
574
+ case 'menu':
575
+ await sendAndReplace(
576
+ `๐Ÿ“ก <b>โ”โ”โ”โ” ู„ูˆุญุฉ ุงู„ุชุญูƒู… โ”โ”โ”โ”</b>\n` +
577
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
578
+ `๐Ÿ‘ค @${CONFIG.TIKTOK_USERNAME}\n` +
579
+ `${isConnected ? `๐ŸŸข ู…ุชุตู„ โ€ข โฑ ${dur(startTime)}` : '๐Ÿ”ด ุบูŠุฑ ู…ุชุตู„'}\n` +
580
+ `๐Ÿ‘ ${formatK(currentViewers)} ู…ุดุงู‡ุฏ โ€ข ๐Ÿ’Ž ${formatK(totalDiamonds)} ู…ุงุณุฉ\n\n` +
581
+ `<i>๐Ÿ“Œ ุงุถุบุท ุฒุฑ ู„ุนุฑุถ ุงู„ุชูุงุตูŠู„ (ุงู„ุฑุณุงู„ุฉ ุงู„ุณุงุจู‚ุฉ ุชูุญุฐู ุชู„ู‚ุงุฆูŠุงู‹)</i>`,
582
+ true,
583
+ [
584
+ [{ text: `๐ŸŽ ุงู„ู‡ุฏุงูŠุง (${totalGifts})`, callback_data: 'gifts' }, { text: `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช (${formatK(totalLikes)})`, callback_data: 'likes' }],
585
+ [{ text: `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช (${totalComments})`, callback_data: 'chatters' }, { text: `โž• ุงู„ู…ุชุงุจุนูŠู† (${totalFollows})`, callback_data: 'followers' }],
586
+ [{ text: `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช (${totalShares})`, callback_data: 'shares' }, { text: `โ“ ุงู„ุฃุณุฆู„ุฉ (${totalQuestions})`, callback_data: 'questions' }],
587
+ [{ text: `๐Ÿ“ฆ๐Ÿ’ฐ ุงู„ุตู†ุงุฏูŠู‚ (${totalEnvelopes})`, callback_data: 'envelopes' }],
588
+ [{ text: '๐Ÿ‘‘ ุฃูƒุซุฑ ุงู„ู…ุชูุงุนู„ูŠู†', callback_data: 'top_active' }],
589
+ [{ text: '๐Ÿ“ˆ ุฅุญุตุงุฆูŠุงุช ู…ูุตู„ุฉ', callback_data: 'stats' }, { text: 'โš”๏ธ ุญุงู„ุฉ PK', callback_data: 'pk_status' }],
590
+ [{ text: '๐Ÿ”ด ุฏุฎูˆู„ ุงู„ุจุซ', url: LIVE() }],
591
+ ],
592
+ 'menu'
593
+ );
594
+ break;
595
+ }
596
+ await answerCallback(cbId);
597
+ }
598
+
599
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• CALLBACK POLLING โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
600
+ async function pollCallbacks() {
601
+ let offset = 0;
602
+ const urls = [];
603
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
604
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
605
+ let idx = 0;
606
+
607
+ while (true) {
608
+ try {
609
+ const base = urls[idx];
610
+ const res = await axios.get(`${base}/getUpdates`, {
611
+ params: { offset, limit: 10, timeout: 30 }, timeout: 35000
612
+ });
613
+ const updates = res.data?.result || [];
614
+ for (const u of updates) {
615
+ offset = u.update_id + 1;
616
+ if (u.callback_query) await handleCallback(u.callback_query);
617
+ if (u.message?.text) await handleTextCommand(u.message);
618
+ }
619
+ idx = 0;
620
+ } catch (e) {
621
+ idx = (idx + 1) % urls.length;
622
+ await new Promise(r => setTimeout(r, idx === 0 ? 5000 : 2000));
623
+ }
624
+ }
625
+ }
626
+
627
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• FLUSH & CLEAR โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
628
+ function clearStats() {
629
+ // ุชู†ุธูŠู ุงู„ุฐุงูƒุฑุฉ
630
+ for (const uid of Object.keys(chattersMap)) {
631
+ if (chattersMap[uid].messages?.length > 30) {
632
+ chattersMap[uid].messages = chattersMap[uid].messages.slice(-30);
633
+ }
634
+ }
635
+ for (const uid of Object.keys(giftersMap)) {
636
+ if (giftersMap[uid].gifts?.length > 10) {
637
+ giftersMap[uid].gifts = giftersMap[uid].gifts.slice(-10);
638
+ }
639
+ }
640
+ if (envelopeWinners.length > 50) {
641
+ envelopeWinners = envelopeWinners.slice(-50);
642
+ }
643
+ if (questionsArr.length > 50) {
644
+ questionsArr = questionsArr.slice(-50);
645
+ }
646
+ }
647
+
648
+ // ุฅุฑุณุงู„ ุชู‚ุฑูŠุฑ ุดุงู…ู„
649
+ async function sendFullStats() {
650
+ if (!isConnected) return;
651
+
652
+ const avgV = maxViewers > 0 ? Math.round((currentViewers + maxViewers) / 2) : currentViewers;
653
+
654
+ let statsMsg = `๐Ÿ“Š๐Ÿ”ฅ <b>โ”โ”โ” ุชู‚ุฑูŠุฑ ุดุงู…ู„ โ”โ”โ”</b>\n`;
655
+ statsMsg += `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n`;
656
+ statsMsg += `๐Ÿ‘ค <b>${CONFIG.TIKTOK_USERNAME}</b> โ€ข <code>@${CONFIG.TIKTOK_USERNAME}</code>\n`;
657
+ statsMsg += `โฑ <b>${dur(startTime)}</b> โ€ข ๐Ÿ“… ${getDate()}\n\n`;
658
+
659
+ statsMsg += `โ”โ”โ” ๐Ÿ‘ ุงู„ู…ุดุงู‡ุฏูŠู† โ”โ”โ”\n`;
660
+ statsMsg += `ุงู„ุญุงู„ูŠูŠู†: <b>${formatK(currentViewers)}</b> | ุงู„ุฃุนู„ู‰: <b>${formatK(maxViewers)}</b> | ุงู„ู…ุชูˆุณุท: ~<b>${formatK(avgV)}</b>\n\n`;
661
+
662
+ statsMsg += `โ”โ”โ” ๐Ÿ“Š ุงู„ุฃุฑู‚ุงู… โ”โ”โ”\n`;
663
+ statsMsg += `๐Ÿ’Ž ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n`;
664
+ statsMsg += `๐ŸŽ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n`;
665
+ statsMsg += `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n`;
666
+ statsMsg += `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช: <b>${totalComments}</b>\n`;
667
+ statsMsg += `โž• ุงู„ู…ุชุงุจุนูŠู†: <b>${totalFollows}</b>\n`;
668
+ statsMsg += `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช: <b>${totalShares}</b>\n`;
669
+ statsMsg += `๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n\n`;
670
+
671
+ statsMsg += `โ”โ”โ” ๐Ÿ† ุฃูุถู„ ุงู„ุฏุงุนู…ูŠู† โ”โ”โ”\n\n${fmtGifters(5)}\n\n`;
672
+ statsMsg += `โ”โ”โ” ๐Ÿ’ฌ ุฃู†ุดุท ุงู„ู…ุนู„ู‚ูŠู† โ”โ”โ”\n\n${fmtChatters(5)}`;
673
+
674
+ await sendAndReplace(statsMsg, false, [
675
+ [{ text: `๐ŸŽ ุงู„ู‡ุฏุงูŠุง (${totalGifts})`, callback_data: 'gifts' }, { text: `โค๏ธ ุงู„ู„ุงูŠูƒุงุช (${formatK(totalLikes)})`, callback_data: 'likes' }],
676
+ [{ text: `๐Ÿ’ฌ ุงู„ู…ุนู„ู‚ูŠู† (${totalComments})`, callback_data: 'chatters' }, { text: `๐Ÿ‘‘ ุงู„ู…ุชูุงุนู„ูŠู†`, callback_data: 'top_active' }],
677
+ [{ text: '๐Ÿ“ฆ๐Ÿ’ฐ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ', callback_data: 'envelopes' }],
678
+ [{ text: '๐Ÿ“ˆ ุชูุงุตูŠู„ ูƒุงู…ู„ุฉ', callback_data: 'stats' }],
679
+ [{ text: '๐Ÿ”ด ุฏุฎูˆู„ ุงู„ุจุซ', url: LIVE() }],
680
+ ], 'report');
681
+ }
682
+
683
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• REPORTS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
684
+ function startReports() {
685
+ if (reportInterval) clearInterval(reportInterval);
686
+ reportInterval = setInterval(() => {
687
+ if (!isConnected) return;
688
+ sendFullStats();
689
+ }, CONFIG.REPORT_INTERVAL * 60000);
690
+ }
691
+
692
+ // ุชู†ุธูŠู ูƒู„ 50 ุฏู‚ูŠู‚ุฉ
693
+ function startFlushTimer() {
694
+ if (flushInterval) clearInterval(flushInterval);
695
+ flushInterval = setInterval(() => {
696
+ clearStats();
697
+ console.log('[Flush] โœ… Memory cleaned');
698
+ // ุฅุฑุณุงู„ ุชู‚ุฑูŠุฑ ุญุชู‰ ู„ูˆ ู„ู… ูŠูุถุบุท ุฒุฑ
699
+ if (isConnected) {
700
+ sendFullStats();
701
+ }
702
+ }, 50 * 60000);
703
+ }
704
+
705
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• HTTP SERVER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
706
+ const server = http.createServer((req, res) => {
707
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
708
+ res.end(`<!DOCTYPE html><html dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Radar v11</title>
709
+ <style>*{margin:0;padding:0;box-sizing:border-box}body{background:#050510;color:#e2e8f0;font-family:system-ui,sans-serif;min-height:100vh;padding:16px}.w{max-width:600px;margin:0 auto}.h{text-align:center;padding:30px;background:linear-gradient(135deg,#4f46e5,#7c3aed);border-radius:20px;margin-bottom:16px}.s{text-align:center;padding:14px;border-radius:14px;margin-bottom:14px;font-weight:700;background:${isConnected?'linear-gradient(135deg,#059669,#10b981)':'linear-gradient(135deg,#dc2626,#ef4444)'}}.g{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:14px}.g>div{background:#1e1b4b;padding:12px;border-radius:12px;text-align:center;border:1px solid #3730a3}.v{font-size:18px;font-weight:800;color:#a78bfa}.l{font-size:10px;color:#64748b;margin-top:3px}.env{background:#1a1040;border-radius:12px;padding:12px;margin-top:10px;border:1px solid #3730a3}</style></head>
710
+ <body><div class="w"><div class="h"><h1>๐Ÿ“ก TikTok Radar</h1><p style="opacity:.7">v11.0 - ุงู„ู†ุณุฎุฉ ุงู„ู…ุญุณู‘ู†ุฉ</p></div>
711
+ <div class="s">${isConnected?'๐ŸŸข ู…ุชุตู„':'๐Ÿ”ด ู…ู†ุชุธุฑ'} โ€ข @${CONFIG.TIKTOK_USERNAME}</div>
712
+ ${isConnected?`<div class="g"><div><div class="v">${formatK(currentViewers)}</div><div class="l">๐Ÿ‘ ุงู„ู…ุดุงู‡ุฏูŠู†</div></div><div><div class="v">${formatK(totalDiamonds)}</div><div class="l">๐Ÿ’Ž ุงู„ู…ุงุณุงุช</div></div><div><div class="v">${totalGifts}</div><div class="l">๐ŸŽ ุงู„ู‡ุฏุงูŠุง</div></div><div><div class="v">${formatK(totalLikes)}</div><div class="l">โค๏ธ ู„ุงูŠูƒุงุช</div></div><div><div class="v">${totalComments}</div><div class="l">๐Ÿ’ฌ ุชุนู„ูŠู‚ุงุช</div></div><div><div class="v">${totalFollows}</div><div class="l">โž• ู…ุชุงุจุนูŠู†</div></div></div>
713
+ <div class="env"><b>๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ:</b> ${totalEnvelopes}<br><b>โฑ ุงู„ู…ุฏุฉ:</b> ${dur(startTime)}</div>`:''}
714
+ <div style="margin-top:20px;text-align:center;font-size:12px;color:#666">
715
+ <b>ุงู„ุฃูˆุงู…ุฑ:</b><br>
716
+ /change username - ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน<br>
717
+ /channel2 CHAT_ID - ู‚ู†ุงุฉ ุซุงู†ูŠุฉ<br>
718
+ /status - ุงู„ุญุงู„ุฉ
719
+ </div>
720
+ </div></body></html>`);
721
+ });
722
+
723
+ server.listen(PORT, '0.0.0.0', () => {
724
+ console.log(`\n๐ŸŽฏ TikTok Radar v11.0 | Port ${PORT} | @${CONFIG.TIKTOK_USERNAME}\n`);
725
+ pollCallbacks();
726
+ setTimeout(startBot, 2000);
727
+ });
728
+
729
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• MAIN BOT โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
730
+ async function startBot() {
731
+ console.log(`[Bot] ๐Ÿ”Ž @${CONFIG.TIKTOK_USERNAME}...`);
732
+ let TikTokLiveConnection, WebcastEvent, ControlEvent;
733
+ try {
734
+ const lib = require('tiktok-live-connector');
735
+ TikTokLiveConnection = lib.TikTokLiveConnection;
736
+ WebcastEvent = lib.WebcastEvent;
737
+ ControlEvent = lib.ControlEvent;
738
+ } catch (e) { console.error('[Bot] โŒ', e.message); setTimeout(startBot, 30000); return; }
739
+
740
+ try {
741
+ const opts = {
742
+ processInitialData: true,
743
+ enableExtendedGiftInfo: true,
744
+ fetchRoomInfoOnConnect: true
745
+ };
746
+
747
+ // Sign API Key
748
+ if (CONFIG.SIGN_API_KEY) {
749
+ opts.signApiKey = CONFIG.SIGN_API_KEY;
750
+ console.log('[Bot] โœ… Sign API Key configured');
751
+ }
752
+
753
+ // Session ู„ู„ู…ุตุงุฏู‚ุฉ ุงู„ูƒุงู…ู„ุฉ
754
+ if (CONFIG.SESSION_ID && CONFIG.SESSION_ID.length > 10) {
755
+ opts.session = {
756
+ cookie: {
757
+ type: 'cookie',
758
+ value: {
759
+ sessionId: CONFIG.SESSION_ID,
760
+ ttTargetIdc: CONFIG.TT_TARGET_IDC
761
+ }
762
+ }
763
+ };
764
+ opts.authenticateWs = true; // ู…ู‡ู…! ู„ู„ุญุตูˆู„ ุนู„ู‰ ุจูŠุงู†ุงุช ูƒุงู…ู„ุฉ
765
+ console.log('[Bot] โœ… Authenticated session configured (authenticateWs: true)');
766
+ }
767
+
768
+ tiktokConnection = new TikTokLiveConnection(CONFIG.TIKTOK_USERNAME, opts);
769
+
770
+ console.log('[Bot] ๐Ÿ“‹ Connection options:', JSON.stringify({
771
+ hasSignApiKey: !!CONFIG.SIGN_API_KEY,
772
+ hasSession: !!(CONFIG.SESSION_ID && CONFIG.SESSION_ID.length > 10),
773
+ authenticateWs: opts.authenticateWs || false,
774
+ ttTargetIdc: CONFIG.TT_TARGET_IDC || 'not set'
775
+ }));
776
+
777
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โœ… CONNECTED โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
778
+ tiktokConnection.on(ControlEvent.CONNECTED, (state) => {
779
+ isConnected = true; startTime = new Date();
780
+ totalGifts=0;totalDiamonds=0;totalLikes=0;totalComments=0;totalFollows=0;
781
+ totalShares=0;totalSuperFans=0;totalQuestions=0;totalEnvelopes=0;totalEmotes=0;
782
+ maxViewers=0;currentViewers=0;
783
+ giftersMap={};followersMap={};chattersMap={};sharersMap={};likersMap={};
784
+ envelopeWinners=[];
785
+ questionsArr=[];pinnedMessages=[];pkActive=false;
786
+ roomTitle = state.roomInfo?.title || '';
787
+
788
+ console.log(`[Bot] โœ… Room: ${state.roomId}`);
789
+ sendBoth(
790
+ `๐Ÿ“กโœจ <b>ุงู„ุจุซ ุงู„ู…ุจุงุดุฑ ุจุฏุฃ!</b>\n` +
791
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
792
+ `๐Ÿ‘ค <b>${CONFIG.TIKTOK_USERNAME}</b>\n` +
793
+ `๐Ÿ”— <code>@${CONFIG.TIKTOK_USERNAME}</code>\n` +
794
+ (roomTitle ? `๐Ÿ“ ${esc(roomTitle)}\n` : '') +
795
+ `โฐ ${getTime()} โ€ข ๐Ÿ“… ${getDate()}\n\n` +
796
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n` +
797
+ `๐ŸŽ‰ <b>ุงู„ุจุซ ุจุฏุฃ! ุงู†ุถู… ุงู„ุขู†!</b>`,
798
+ false,
799
+ [
800
+ [{ text: '๐Ÿ”ด ุฏุฎูˆู„ ุงู„ุจุซ ุงู„ู…ุจุงุดุฑ', url: LIVE() }],
801
+ [{ text: '๐Ÿ“Š ู„ูˆุญุฉ ุงู„ุชุญูƒู…', callback_data: 'menu' }]
802
+ ]
803
+ );
804
+ startReports();
805
+ startFlushTimer();
806
+ });
807
+
808
+ tiktokConnection.on(ControlEvent.DISCONNECTED, () => {
809
+ isConnected = false;
810
+ if (reportInterval) clearInterval(reportInterval);
811
+ if (flushInterval) clearInterval(flushInterval);
812
+ scheduleReconnect(30000);
813
+ });
814
+
815
+ tiktokConnection.on(ControlEvent.ERROR, (err) => console.error('[Bot] โš ๏ธ', err?.info || err?.message || err));
816
+
817
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ”ด STREAM END โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
818
+ tiktokConnection.on(WebcastEvent.STREAM_END, () => {
819
+ isConnected = false;
820
+ if (reportInterval) clearInterval(reportInterval);
821
+ if (flushInterval) clearInterval(flushInterval);
822
+ sendBoth(
823
+ `๐Ÿ”ด <b>ุงู†ุชู‡ู‰ ุงู„ุจุซ!</b>\n` +
824
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
825
+ `๐Ÿ‘ค <b>${CONFIG.TIKTOK_USERNAME}</b>\n` +
826
+ `โฑ ุงู„ู…ุฏุฉ: <b>${dur(startTime)}</b>\n` +
827
+ `๐Ÿ“… ${getDate()}\n\n` +
828
+ `โ”โ”โ” ๐Ÿ“Š ุงู„ู…ู„ุฎุต ุงู„ู†ู‡ุงุฆูŠ โ”โ”โ”\n` +
829
+ `๐Ÿ’Ž ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` +
830
+ `๐ŸŽ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n` +
831
+ `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n` +
832
+ `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช: <b>${totalComments}</b>\n` +
833
+ `โž• ุงู„ู…ุชุงุจุนูŠู†: <b>${totalFollows}</b>\n` +
834
+ `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช: <b>${totalShares}</b>\n` +
835
+ `๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n\n` +
836
+ `โ”โ”โ” ๐Ÿ† ุฃูุถู„ ุงู„ุฏุงุนู…ูŠู† โ”โ”โ”\n\n${fmtGifters(5)}\n\n` +
837
+ `โ”โ”โ” ๐Ÿ’ฌ ุฃู†ุดุท ุงู„ู…ุนู„ู‚ูŠู† โ”โ”โ”\n\n${fmtChatters(5)}\n\n` +
838
+ `โœจ <b>ุดูƒุฑุงู‹ ู„ู„ุฌู…ูŠุน!</b>`
839
+ );
840
+ scheduleReconnect(60000);
841
+ });
842
+
843
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ’ฌ CHAT โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
844
+ tiktokConnection.on(WebcastEvent.CHAT, (data) => {
845
+ totalComments++;
846
+ const uid = data.user?.userId || data.user?.uniqueId || 'x';
847
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
848
+ const uname = data.user?.uniqueId || '';
849
+ const comment = data.comment || '';
850
+ if (!chattersMap[uid]) chattersMap[uid] = { name, username: uname, count: 0, messages: [] };
851
+ chattersMap[uid].count++;
852
+ if (comment) {
853
+ chattersMap[uid].messages.push(comment);
854
+ if (chattersMap[uid].messages.length > 20) {
855
+ chattersMap[uid].messages = chattersMap[uid].messages.slice(-20);
856
+ }
857
+ }
858
+ });
859
+
860
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐ŸŽ GIFT โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
861
+ tiktokConnection.on(WebcastEvent.GIFT, (data) => {
862
+ const uid = data.user?.userId || data.user?.uniqueId || 'x';
863
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
864
+ const uname = data.user?.uniqueId || '';
865
+ const gn = data.giftName || data.extendedGiftInfo?.name || 'Gift';
866
+ const gnAr = getArabicGiftName(gn);
867
+ const gt = data.giftType ?? 0;
868
+ const rc = data.repeatCount ?? 1;
869
+ const re = data.repeatEnd ?? true;
870
+ let dc = data.diamondCount || data.extendedGiftInfo?.diamondCount || data.extendedGiftInfo?.diamond_count || data.gift?.diamond_count || data.giftDetails?.diamondCount || 0;
871
+ if (gt === 1 && re === false) return;
872
+ const cost = dc * rc;
873
+ totalGifts++; totalDiamonds += cost;
874
+ if (!giftersMap[uid]) giftersMap[uid] = { name, username: uname, coins: 0, count: 0, gifts: [] };
875
+ giftersMap[uid].coins += cost; giftersMap[uid].count++;
876
+ giftersMap[uid].gifts.push(gn);
877
+ if (giftersMap[uid].gifts.length > 10) {
878
+ giftersMap[uid].gifts = giftersMap[uid].gifts.slice(-10);
879
+ }
880
+ if (pkActive) {
881
+ if (!pkInfo.pkGifts[uid]) pkInfo.pkGifts[uid] = { name, username: uname, coins: 0 };
882
+ pkInfo.pkGifts[uid].coins += cost;
883
+ }
884
+ console.log(`[๐ŸŽ] ${name}: ${gnAr} = ${cost}๐Ÿ’Ž`);
885
+ });
886
+
887
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โค๏ธ LIKE โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
888
+ tiktokConnection.on(WebcastEvent.LIKE, (data) => {
889
+ const likes = data.likeCount || 1;
890
+ totalLikes += likes;
891
+ const uid = data.user?.userId || data.user?.uniqueId || 'x';
892
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
893
+ const uname = data.user?.uniqueId || '';
894
+ if (!likersMap[uid]) likersMap[uid] = { name, username: uname, count: 0 };
895
+ likersMap[uid].count += likes;
896
+ });
897
+
898
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โž• FOLLOW โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
899
+ tiktokConnection.on(WebcastEvent.FOLLOW, (data) => {
900
+ totalFollows++;
901
+ const uid = data.user?.userId || data.user?.uniqueId || Date.now();
902
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
903
+ const uname = data.user?.uniqueId || '';
904
+ followersMap[uid] = { name, username: uname, time: Date.now() };
905
+ });
906
+
907
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ†ช๏ธ SHARE โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
908
+ tiktokConnection.on(WebcastEvent.SHARE, (data) => {
909
+ totalShares++;
910
+ const uid = data.user?.uniqueId || 'x';
911
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
912
+ if (!sharersMap[uid]) sharersMap[uid] = { name, username: uid, count: 0 };
913
+ sharersMap[uid].count++;
914
+ });
915
+
916
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ‘ VIEWERS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
917
+ tiktokConnection.on(WebcastEvent.ROOM_USER, (data) => {
918
+ currentViewers = data.viewerCount || 0;
919
+ if (currentViewers > maxViewers) maxViewers = currentViewers;
920
+ });
921
+
922
+ tiktokConnection.on(WebcastEvent.MEMBER, () => {});
923
+ tiktokConnection.on(WebcastEvent.EMOTE, () => { totalEmotes++; });
924
+
925
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“ฆ ENVELOPE - ุตู†ุฏูˆู‚ / ุญู‚ูŠุจุฉ ุนู…ู„ุงุช โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
926
+ tiktokConnection.on(WebcastEvent.ENVELOPE, (data) => {
927
+ totalEnvelopes++;
928
+
929
+ // ุทุจุงุนุฉ ูƒู„ ุงู„ุจูŠุงู†ุงุช ู„ูุญุตู‡ุง
930
+ console.log('[๐Ÿ“ฆ ENVELOPE RAW]', JSON.stringify(data, null, 2));
931
+
932
+ const env = data.envelopeInfo || data;
933
+ if (env) {
934
+ // ู…ุญุงูˆู„ุฉ ุงุณุชุฎุฑุงุฌ ุงู„ุจูŠุงู†ุงุช ู…ู† ู…ุฎุชู„ู ุงู„ู…ูˆุงู‚ุน ุงู„ู…ู…ูƒู†ุฉ
935
+ const senderName = env.sendUserName || env.senderNickname || data.user?.nickname || '?';
936
+ const senderUsername = env.sendUserUniqueId || env.senderUniqueId || data.user?.uniqueId || '';
937
+ const diamonds = env.diamondCount || env.coins || data.diamonds || 0;
938
+ const peopleCount = env.peopleCount || env.maxUserCount || 0;
939
+ const envelopeId = env.envelopeId || env.id || '';
940
+
941
+ // ุชุญุฏูŠุฏ ุงู„ู†ูˆุน ุจุดูƒู„ ุฃูุถู„
942
+ let envType = 'chest';
943
+ if (env.envelopeType === 2 || env.envelopeBusinessType === 2) {
944
+ envType = 'coinbag';
945
+ } else if (String(env.description || '').toLowerCase().includes('coin') ||
946
+ String(env.description || '').toLowerCase().includes('ุญู‚ูŠุจุฉ') ||
947
+ String(env.title || '').toLowerCase().includes('coin') ||
948
+ String(data.common?.describe || '').toLowerCase().includes('coin')) {
949
+ envType = 'coinbag';
950
+ }
951
+
952
+ const typeIcon = envType === 'coinbag' ? '๐Ÿ’ฐ' : '๐Ÿ“ฆ';
953
+ const typeName = envType === 'coinbag' ? 'ุญู‚ูŠุจุฉ ุนู…ู„ุงุช' : 'ุตู†ุฏูˆู‚ ูƒู†ุฒ';
954
+
955
+ // ุงุณุชุฎุฑุงุฌ ุงู„ูุงุฆุฒูŠู† ู…ู† ู…ุฎุชู„ู ุงู„ู…ุตุงุฏุฑ ุงู„ู…ู…ูƒู†ุฉ
956
+ const winners = [];
957
+
958
+ // ุงู„ู…ุตุฏุฑ 1: envelopeGrabUserList
959
+ const grabList = env.envelopeGrabUserList || env.grabUserList || env.winnerList || env.winners || [];
960
+ for (const w of grabList) {
961
+ winners.push({
962
+ name: w.nickname || w.nickName || w.uniqueId || w.userName || '?',
963
+ username: w.uniqueId || w.unique_id || '',
964
+ coins: w.diamondCount || w.coinCount || w.coins || w.amount || 0,
965
+ });
966
+ }
967
+
968
+ // ุงู„ู…ุตุฏุฑ 2: envelopeGrabRecordList
969
+ const recordList = env.envelopeGrabRecordList || [];
970
+ for (const r of recordList) {
971
+ const user = r.user || r;
972
+ winners.push({
973
+ name: user.nickname || user.nickName || user.uniqueId || '?',
974
+ username: user.uniqueId || '',
975
+ coins: r.diamondCount || r.coinCount || r.grabDiamond || 0,
976
+ });
977
+ }
978
+
979
+ console.log(`[๐Ÿ“ฆ] ${typeName} ู…ู† ${senderName}: ${diamonds}๐Ÿ’Ž ู„ู„ู€ ${peopleCount} ุดุฎุต | ุงู„ูุงุฆุฒูŠู†: ${winners.length}`);
980
+
981
+ envelopeWinners.push({
982
+ type: envType,
983
+ sender: senderName,
984
+ senderUsername,
985
+ diamonds,
986
+ peopleCount,
987
+ winners,
988
+ envelopeId,
989
+ time: new Date()
990
+ });
991
+
992
+ let winnerText = '';
993
+ if (winners.length) {
994
+ winnerText = `\n\n๐Ÿ† <b>ุงู„ูุงุฆุฒูŠู†:</b>\n` + winners.map((w, i) =>
995
+ ` ${i + 1}. ๐Ÿ‘ค <b>${esc(w.name)}</b> ${w.username ? `<code>@${w.username}</code>` : ''}\n ๐Ÿช™ ุญุตู„ ุนู„ู‰: <b>${formatK(w.coins)}</b> ุนู…ู„ุฉ`
996
+ ).join('\n');
997
+ } else {
998
+ winnerText = `\n\nโณ <i>ุงู„ูุงุฆุฒูŠู† ุณูŠุธู‡ุฑูˆู† ุจุนุฏ ุงู†ุชู‡ุงุก ุงู„ุตู†ุฏูˆู‚...</i>`;
999
+ }
1000
+
1001
+ sendBoth(
1002
+ `${typeIcon}โœจ <b>${typeName}!</b>\n` +
1003
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
1004
+ `๐Ÿ†” ุฑู‚ู…: <code>${envelopeId}</code>\n` +
1005
+ `๐Ÿ‘ค ุงู„ู…ุฑุณู„: <b>${esc(senderName)}</b> ${senderUsername ? `<code>@${senderUsername}</code>` : ''}\n` +
1006
+ `๐Ÿ’Ž <b>${formatK(diamonds)}</b> ู…ุงุณุฉ โ€ข ๐Ÿ‘ฅ <b>${peopleCount}</b> ุดุฎุต` +
1007
+ winnerText
1008
+ );
1009
+ }
1010
+ });
1011
+
1012
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“ฆ ู…ุญุงูˆู„ุฉ ุงู„ุชู‚ุงุท ุฃุญุฏุงุซ ุฃุฎุฑู‰ ู„ู„ุตู†ุงุฏูŠู‚ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1013
+ const envelopeEvents = [
1014
+ 'envelopeGrab', 'envelopeResult', 'envelopeOpen', 'envelopePortal',
1015
+ 'treasureBox', 'treasureChest', 'goodyBag', 'goody_bag',
1016
+ 'coinBag', 'coin_bag', 'luckyBag', 'lucky_bag'
1017
+ ];
1018
+
1019
+ for (const evtName of envelopeEvents) {
1020
+ try {
1021
+ tiktokConnection.on(evtName, (data) => {
1022
+ console.log(`[๐Ÿ“ฆ ${evtName.toUpperCase()}]`, JSON.stringify(data, null, 2));
1023
+
1024
+ // ู…ุญุงูˆู„ุฉ ุงุณุชุฎุฑุงุฌ ุงู„ูุงุฆุฒูŠู†
1025
+ const winners = extractWinners(data);
1026
+ if (winners.length > 0) {
1027
+ updateLastEnvelopeWithWinners(winners);
1028
+ }
1029
+ });
1030
+ } catch (e) {}
1031
+ }
1032
+
1033
+ // ุงู„ุงุณุชู…ุงุน ู„ู€ BARRAGE ู‚ุฏ ูŠุญุชูˆูŠ ุนู„ู‰ ู…ุนู„ูˆู…ุงุช ุงู„ุตู†ุงุฏูŠู‚
1034
+ try {
1035
+ tiktokConnection.on(WebcastEvent.BARRAGE, (data) => {
1036
+ const content = JSON.stringify(data).toLowerCase();
1037
+ if (content.includes('envelope') || content.includes('treasure') ||
1038
+ content.includes('chest') || content.includes('grab') ||
1039
+ content.includes('coin') || content.includes('winner')) {
1040
+ console.log('[๐Ÿ“ฆ BARRAGE - Envelope Related]', JSON.stringify(data, null, 2));
1041
+
1042
+ const winners = extractWinners(data);
1043
+ if (winners.length > 0) {
1044
+ updateLastEnvelopeWithWinners(winners);
1045
+ }
1046
+ }
1047
+ });
1048
+ } catch (e) {}
1049
+
1050
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ“ QUESTION โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1051
+ try { tiktokConnection.on(WebcastEvent.QUESTION_NEW, (data) => {
1052
+ totalQuestions++;
1053
+ const q = data.details?.questionText || '';
1054
+ const name = data.details?.user?.nickname || '?';
1055
+ if (q) questionsArr.push({ name, text: q, time: Date.now() });
1056
+ }); } catch (e) {}
1057
+
1058
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โญ SUPER FAN โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1059
+ try { tiktokConnection.on(WebcastEvent.SUPER_FAN, (data) => {
1060
+ totalSuperFans++;
1061
+ const msg = data.content?.defaultPattern || data.commonBarrageContent?.defaultPattern || '';
1062
+ sendBoth(`โญ๐ŸŒŸ <b>ุณูˆุจุฑ ูุงู† ุฌุฏูŠุฏ!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n${esc(msg) || '๐Ÿ‘‘ ู…ุณุชุฎุฏู… ุฃุตุจุญ ุณูˆุจุฑ ูุงู†!'}`);
1063
+ }); } catch (e) {}
1064
+
1065
+ try { tiktokConnection.on(WebcastEvent.SUPER_FAN_JOIN, () => {}); } catch (e) {}
1066
+ try { tiktokConnection.on(WebcastEvent.SUPER_FAN_BOX, (data) => {
1067
+ if (data.envelopeInfo) sendBoth(`โญ๐Ÿ“ฆ <b>ุตู†ุฏูˆู‚ ุณูˆุจุฑ ูุงู†!</b>`);
1068
+ }); } catch (e) {}
1069
+
1070
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“Œ PIN โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1071
+ try { tiktokConnection.on(WebcastEvent.ROOM_PIN, (data) => {
1072
+ const by = data.operator?.nickname || '?';
1073
+ const chat = data.chatMessage?.comment || '';
1074
+ if (chat) sendBoth(`๐Ÿ“Œ <b>ุฑุณุงู„ุฉ ู…ุซุจุชุฉ</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n๐Ÿ‘ค <b>${esc(by)}</b>\n๐Ÿ’ฌ <i>"${esc(chat)}"</i>`, true);
1075
+ }); } catch (e) {}
1076
+
1077
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โš”๏ธ PK โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1078
+ tiktokConnection.on(WebcastEvent.LINK_MIC_BATTLE, (data) => {
1079
+ pkActive = true;
1080
+ pkInfo = { battleId: data.battleId || '', participantDetails: [], ourScore: 0, theirScore: 0, startTime: new Date(), pkGifts: {} };
1081
+ const details = [];
1082
+ for (const [k, info] of Object.entries(data.anchorInfo || {})) {
1083
+ const u = info.user || info || {};
1084
+ const did = u.displayId || u.uniqueId || '';
1085
+ const nn = u.nickName || u.nickname || did || 'ู…ุฌู‡ูˆู„';
1086
+ if (did || nn !== 'ู…ุฌู‡ูˆู„') details.push({ name: nn, username: did });
1087
+ }
1088
+ pkInfo.participantDetails = details;
1089
+ const opp = details.find(p => p.username !== CONFIG.TIKTOK_USERNAME && p.name !== CONFIG.TIKTOK_USERNAME) || details[1] || null;
1090
+
1091
+ let msg = `โš”๏ธ๐Ÿ”ฅ <b>ุฌูˆู„ุฉ PK ุฌุฏูŠุฏุฉ!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n`;
1092
+ msg += `๐Ÿ  <b>${esc(CONFIG.TIKTOK_USERNAME)}</b>\n <code>@${CONFIG.TIKTOK_USERNAME}</code>\n\n ๐Ÿ†š\n\n`;
1093
+ if (opp) msg += `๐ŸฅŠ <b>${esc(opp.name)}</b>\n <code>@${opp.username || '?'}</code>\n\n`;
1094
+ else msg += `๐ŸฅŠ โณ ุฌุงุฑูŠ ุงู„ุชุญู…ูŠู„...\n\n`;
1095
+ msg += `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿš€ <b>ุงุฏุนู…ูˆุง ุงู„ุจุซ!</b>`;
1096
+ sendBoth(msg, false, [
1097
+ [{ text: '๐Ÿ”ด ุงุฏุฎู„ ูˆุงุฏุนู…!', url: LIVE() }],
1098
+ [{ text: 'โš”๏ธ ู†ุชูŠุฌุฉ PK', callback_data: 'pk_status' }]
1099
+ ]);
1100
+ });
1101
+
1102
+ tiktokConnection.on(WebcastEvent.LINK_MIC_ARMIES, (data) => {
1103
+ if (pkActive && data.totalDiamondCount) pkInfo.ourScore = data.totalDiamondCount;
1104
+ });
1105
+
1106
+ try { tiktokConnection.on(WebcastEvent.LINK_MIC_BATTLE_PUNISH_FINISH, () => {
1107
+ pkActive = false;
1108
+ const pkG = Object.values(pkInfo.pkGifts).sort((a, b) => b.coins - a.coins).slice(0, 5)
1109
+ .map((g, i) => `${medals[i]} <b>${esc(g.name)}</b>: ${formatK(g.coins)} ๐Ÿ’Ž`).join('\n') || 'ู„ุง ูŠูˆุฌุฏ';
1110
+ sendBoth(`๐Ÿ† <b>ุงู†ุชู‡ุช PK!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n๐Ÿ’Ž <b>${formatK(pkInfo.ourScore)}</b> โ€ข โฑ ${dur(pkInfo.startTime)}\n\n๐Ÿ† ุงู„ุฏุงุนู…ูŠู†:\n${pkG}\n\nโœจ <b>ุดูƒุฑุงู‹ ู„ู„ุฌู…ูŠุน!</b>`);
1111
+ }); } catch (e) {}
1112
+
1113
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐ŸŽฏ GOAL โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1114
+ try { tiktokConnection.on(WebcastEvent.GOAL_UPDATE, (data) => {
1115
+ const d = data.goal?.description || '';
1116
+ if (d) sendBoth(`๐ŸŽฏ <b>ุชุญุฏูŠุซ ุงู„ู‡ุฏู!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ“‹ ${esc(d)}`, true);
1117
+ }); } catch (e) {}
1118
+
1119
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ—ณ๏ธ POLL โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1120
+ try { tiktokConnection.on(WebcastEvent.POLL_MESSAGE, (data) => {
1121
+ const t = data.pollBasicInfo?.title || '';
1122
+ if (t) sendBoth(`๐Ÿ—ณ๏ธ <b>ุชุตูˆูŠุช!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ“‹ <b>${esc(t)}</b>`, true);
1123
+ }); } catch (e) {}
1124
+
1125
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ›’ SHOPPING โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1126
+ try { tiktokConnection.on(WebcastEvent.OEC_LIVE_SHOPPING, (data) => {
1127
+ const s = data.shopData;
1128
+ if (s?.title) sendBoth(`๐Ÿ›’ <b>ู…ู†ุชุฌ!</b>\n๐Ÿ“ฆ ${esc(s.title)}${s.priceString ? `\n๐Ÿ’ฐ ${esc(s.priceString)}` : ''}`, true);
1129
+ }); } catch (e) {}
1130
+
1131
+ try { tiktokConnection.on(WebcastEvent.RANK_UPDATE, () => {}); } catch (e) {}
1132
+ try { tiktokConnection.on(WebcastEvent.RANK_TEXT, (data) => {
1133
+ if (data.ownerIdxAfterUpdate && data.ownerIdxBeforeUpdate && data.ownerIdxAfterUpdate < data.ownerIdxBeforeUpdate)
1134
+ sendBoth(`๐Ÿ†๐Ÿ“ˆ ุงุฑุชูุน ุงู„ุชุฑุชูŠุจ! #${data.ownerIdxBeforeUpdate} โ†’ #${data.ownerIdxAfterUpdate} ๐Ÿ”ฅ`, true);
1135
+ }); } catch (e) {}
1136
+ tiktokConnection.on(WebcastEvent.LIVE_INTRO, () => {});
1137
+ try { tiktokConnection.on(WebcastEvent.ROOM_MESSAGE, () => {}); } catch (e) {}
1138
+ try { tiktokConnection.on(WebcastEvent.CAPTION_MESSAGE, () => {}); } catch (e) {}
1139
+
1140
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“Š ุชุณุฌูŠู„ ูƒู„ ุงู„ุฃุญุฏุงุซ ุจุฏูˆู† ุงุณุชุซู†ุงุก โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1141
+ // ู„ุง ู†ุชุฌุงู‡ู„ ุฃูŠ ุดูŠ - ู†ุณุฌู„ ูƒู„ ุญุฏุซ ุจุฃูˆู„ 200 ุญุฑู
1142
+ const knownSkipEvents = new Set([
1143
+ // ูู‚ุท ุงู„ุฃุญุฏุงุซ ุงู„ูƒุซูŠุฑุฉ ุฌุฏุงู‹ ุงู„ู„ูŠ ุชู…ู„ุฃ ุงู„ู€ Logs
1144
+ 'WebcastChatMessage', 'WebcastLikeMessage',
1145
+ 'WebcastRoomUserSeqMessage',
1146
+ ]);
1147
+
1148
+ // ุนุฏุงุฏ ู„ุชุณุฌูŠู„ ูƒู„ ุฃู†ูˆุงุน ุงู„ุฃุญุฏุงุซ ุงู„ู„ูŠ ุฌุช
1149
+ const seenEventTypes = new Set();
1150
+
1151
+ tiktokConnection.on(ControlEvent.DECODED_DATA, (eventType, decodedData, binary) => {
1152
+ const lowerType = (eventType || '').toLowerCase();
1153
+
1154
+ // โœ… ุชุณุฌูŠู„ ูƒู„ ู†ูˆุน ุญุฏุซ ูŠู…ุฑ ู…ุฑุฉ ูˆุญุฏุฉ
1155
+ if (!seenEventTypes.has(eventType)) {
1156
+ seenEventTypes.add(eventType);
1157
+ console.log(`[๐Ÿ†• NEW EVENT TYPE SEEN: ${eventType}] โ† ุฃูˆู„ ู…ุฑุฉ ูŠุธู‡ุฑ ู‡ุงู„ู†ูˆุน!`);
1158
+ }
1159
+
1160
+ // โœ… ุชุณุฌูŠู„ ูƒู„ ุญุฏุซ ุบูŠุฑ ู…ุนุฑูˆู
1161
+ if (!knownSkipEvents.has(eventType)) {
1162
+ const dataStr = JSON.stringify(decodedData || {});
1163
+ // ุณุฌ๏ฟฝ๏ฟฝ ุงุณู… ุงู„ุญุฏุซ + ุฃูˆู„ 300 ุญุฑู ุจุณ
1164
+ console.log(`[๐Ÿ“ก ${eventType}] ${dataStr.substring(0, 300)}`);
1165
+
1166
+ // ุฅุฐุง ู…ุชุนู„ู‚ ุจุตู†ุฏูˆู‚ ุณุฌู„ ูƒุงู…ู„
1167
+ if (lowerType.includes('envelope') || lowerType.includes('treasure') ||
1168
+ lowerType.includes('chest') || lowerType.includes('grab') ||
1169
+ lowerType.includes('goody') || lowerType.includes('portal') ||
1170
+ lowerType.includes('lucky') || lowerType.includes('coin') ||
1171
+ lowerType.includes('bag') || lowerType.includes('box')) {
1172
+ console.log(`[๐Ÿ“ฆ FULL ${eventType}]`, JSON.stringify(decodedData, null, 2));
1173
+
1174
+ const winners = extractWinners(decodedData);
1175
+ if (winners.length > 0) {
1176
+ updateLastEnvelopeWithWinners(winners);
1177
+ }
1178
+ }
1179
+
1180
+ // ุญุชู‰ ู„ูˆ ู…ุง ู†ุนุฑู ุงุณู… ุงู„ุญุฏุซุŒ ู†ูุญุต ุงู„ู…ุญุชูˆู‰
1181
+ if (dataStr.toLowerCase().includes('envelope') ||
1182
+ dataStr.toLowerCase().includes('diamond') ||
1183
+ dataStr.toLowerCase().includes('grab')) {
1184
+ console.log(`[๐Ÿ“ฆ DATA-MATCH ${eventType}]`, JSON.stringify(decodedData, null, 2));
1185
+
1186
+ // ู…ุญุงูˆู„ุฉ ู…ุนุงู„ุฌุฉ ูƒุฃู†ู‡ ุตู†ุฏูˆู‚
1187
+ try {
1188
+ const env = decodedData?.envelopeInfo || decodedData;
1189
+ if (env && (env.diamondCount || env.sendUserName || env.envelopeId)) {
1190
+ totalEnvelopes++;
1191
+ const senderName = env.sendUserName || env.senderNickname || '?';
1192
+ const senderUsername = env.sendUserUniqueId || env.senderUniqueId || '';
1193
+ const diamonds = env.diamondCount || env.coins || 0;
1194
+ const peopleCount = env.peopleCount || env.maxUserCount || 0;
1195
+ const envelopeId = env.envelopeId || env.id || '';
1196
+
1197
+ let envType = 'chest';
1198
+ if (env.envelopeType === 2 || env.envelopeBusinessType === 2) envType = 'coinbag';
1199
+
1200
+ const typeIcon = envType === 'coinbag' ? '๐Ÿ’ฐ' : '๐Ÿ“ฆ';
1201
+ const typeName = envType === 'coinbag' ? 'ุญู‚ูŠุจุฉ ุนู…ู„ุงุช' : 'ุตู†ุฏูˆู‚ ูƒู†ุฒ';
1202
+
1203
+ const winners = extractWinners(decodedData);
1204
+
1205
+ envelopeWinners.push({
1206
+ type: envType, sender: senderName, senderUsername,
1207
+ diamonds, peopleCount, winners, envelopeId, time: new Date()
1208
+ });
1209
+
1210
+ let winnerText = '';
1211
+ if (winners.length) {
1212
+ winnerText = `\n\n๐Ÿ† <b>ุงู„ูุงุฆุฒูŠู†:</b>\n` + winners.map((w, i) =>
1213
+ ` ${i + 1}. ๐Ÿ‘ค <b>${esc(w.name)}</b> ${w.username ? `<code>@${w.username}</code>` : ''}\n ๐Ÿช™ ุญุตู„ ุนู„ู‰: <b>${formatK(w.coins)}</b> ุนู…ู„ุฉ`
1214
+ ).join('\n');
1215
+ } else {
1216
+ winnerText = `\n\nโณ <i>ุงู„ูุงุฆุฒูŠู† ุณูŠุธู‡ุฑูˆู† ู„ุงุญู‚ุงู‹...</i>`;
1217
+ }
1218
+
1219
+ sendBoth(
1220
+ `${typeIcon}โœจ <b>${typeName}!</b>\n` +
1221
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
1222
+ `๐Ÿ†” ุฑู‚ู…: <code>${envelopeId}</code>\n` +
1223
+ `๐Ÿ‘ค ุงู„ู…ุฑุณู„: <b>${esc(senderName)}</b> ${senderUsername ? `<code>@${senderUsername}</code>` : ''}\n` +
1224
+ `๐Ÿ’Ž <b>${formatK(diamonds)}</b> ู…ุงุณุฉ โ€ข ๐Ÿ‘ฅ <b>${peopleCount}</b> ุดุฎุต` +
1225
+ winnerText
1226
+ );
1227
+
1228
+ console.log(`[๐Ÿ“ฆ โœ… CAUGHT FROM DECODED] ${typeName} ู…ู† ${senderName}: ${diamonds}๐Ÿ’Ž`);
1229
+ }
1230
+ } catch (e) {
1231
+ console.log('[๐Ÿ“ฆ Parse Error]', e.message);
1232
+ }
1233
+ }
1234
+ }
1235
+ });
1236
+
1237
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“‹ ุนุฑุถ ูƒู„ ุงู„ุฃุญุฏุงุซ ุงู„ู…ุชูˆูุฑุฉ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1238
+ console.log('[Bot] ๐Ÿ“‹ Available WebcastEvents:', Object.keys(WebcastEvent).join(', '));
1239
+ console.log('[Bot] ๐Ÿ“‹ Available ControlEvents:', Object.keys(ControlEvent).join(', '));
1240
+
1241
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“ก RAW DATA - ุงู„ุชู‚ุงุท ุงู„ุจูŠุงู†ุงุช ุงู„ุฎุงู… ุบูŠุฑ ุงู„ู…๏ฟฝ๏ฟฝุฑูˆูุฉ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1242
+ tiktokConnection.on(ControlEvent.RAW_DATA, (messageTypeName, binary) => {
1243
+ const lowerName = (messageTypeName || '').toLowerCase();
1244
+ // ู†ุณุฌู„ ูู‚ุท ุงู„ุฑุณุงุฆู„ ุงู„ุบูŠุฑ ู…ุนุฑูˆูุฉ ุฃูˆ ุงู„ู…ุชุนู„ู‚ุฉ ุจุงู„ุจูˆุงุจุฉ
1245
+ if (lowerName.includes('envelope') || lowerName.includes('portal') ||
1246
+ lowerName.includes('goody') || lowerName.includes('treasure') ||
1247
+ lowerName.includes('bag') || lowerName.includes('box') ||
1248
+ lowerName.includes('grab') || lowerName.includes('lucky') ||
1249
+ lowerName.includes('reward') || lowerName.includes('coin') ||
1250
+ lowerName.includes('asset')) {
1251
+ console.log(`[๐Ÿ”ด RAW_DATA: ${messageTypeName}] binary size: ${binary?.length || 0} bytes`);
1252
+ }
1253
+ });
1254
+
1255
+ // ู…ุญุงูˆู„ุฉ ุงู„ุงุณุชู…ุงุน ู„ูƒู„ ุงู„ุฃุญุฏุงุซ ุงู„ู…ุชูˆูุฑุฉ ููŠ ุงู„ู…ูƒุชุจุฉ
1256
+ const allWebcastEvents = Object.values(WebcastEvent);
1257
+ for (const evt of allWebcastEvents) {
1258
+ const evtLower = (evt || '').toLowerCase();
1259
+ // ุงู„ุฃุญุฏุงุซ ุงู„ู„ูŠ ู…ุง ุณุฌู„ู†ุงู‡ุง ูŠุฏูˆูŠุงู‹
1260
+ if (evtLower.includes('envelope') || evtLower.includes('treasure') ||
1261
+ evtLower.includes('goody') || evtLower.includes('portal') ||
1262
+ evtLower.includes('bag') || evtLower.includes('box') ||
1263
+ evtLower.includes('capsule') || evtLower.includes('boost') ||
1264
+ evtLower.includes('toast') || evtLower.includes('notice') ||
1265
+ evtLower.includes('bottom') || evtLower.includes('gift_broadcast')) {
1266
+ try {
1267
+ tiktokConnection.on(evt, (data) => {
1268
+ console.log(`[๐ŸŽฏ AUTO-LISTEN ${evt}]`, JSON.stringify(data, null, 2));
1269
+
1270
+ // ู…ุญุงูˆู„ุฉ ู…ุนุงู„ุฌุฉ ูƒุตู†ุฏูˆู‚
1271
+ const winners = extractWinners(data);
1272
+ if (data?.envelopeInfo || data?.diamondCount || data?.sendUserName) {
1273
+ totalEnvelopes++;
1274
+ const env = data.envelopeInfo || data;
1275
+ const senderName = env.sendUserName || '?';
1276
+ const diamonds = env.diamondCount || 0;
1277
+ const peopleCount = env.peopleCount || 0;
1278
+
1279
+ envelopeWinners.push({
1280
+ type: 'chest', sender: senderName, senderUsername: '',
1281
+ diamonds, peopleCount, winners, envelopeId: '', time: new Date()
1282
+ });
1283
+
1284
+ sendBoth(
1285
+ `๐Ÿ“ฆโœจ <b>ุตู†ุฏูˆู‚/ุจูˆุงุจุฉ!</b> (via ${evt})\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
1286
+ `๐Ÿ‘ค <b>${esc(senderName)}</b>\n๐Ÿ’Ž <b>${formatK(diamonds)}</b> ู…ุงุณุฉ`
1287
+ );
1288
+ }
1289
+ if (winners.length > 0) {
1290
+ updateLastEnvelopeWithWinners(winners);
1291
+ }
1292
+ });
1293
+ console.log(`[Bot] ๐Ÿ‘‚ Auto-listening: ${evt}`);
1294
+ } catch (e) {}
1295
+ }
1296
+ }
1297
+
1298
+ console.log('[Bot] ๐Ÿ”Œ Connecting...');
1299
+ await tiktokConnection.connect();
1300
+ } catch (err) {
1301
+ console.error('[Bot] โŒ', err.message || err);
1302
+ isConnected = false;
1303
+ scheduleReconnect(60000);
1304
+ }
1305
+ }
1306
+
1307
+ function scheduleReconnect(d) {
1308
+ if (reconnectTimer) clearTimeout(reconnectTimer);
1309
+ console.log(`[Bot] ๐Ÿ”„ ${d / 1000}s...`);
1310
+ reconnectTimer = setTimeout(() => { reconnectTimer = null; if (!isConnected) startBot(); }, d);
1311
+ }
1312
+
1313
+ process.on('uncaughtException', e => console.error('[!]', e.message));
1314
+ process.on('unhandledRejection', r => console.error('[!]', r));
1315
+ setInterval(() => { http.get(`http://localhost:${PORT}`, r => r.resume()).on('error', () => {}); }, 60000);
package.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "tiktok-radar-v11",
3
+ "version": "11.0.0",
4
+ "main": "bot.js",
5
+ "dependencies": {
6
+ "axios": "^1.7.0",
7
+ "tiktok-live-connector": "2.1.0"
8
+ }
9
+ }