Reooiq commited on
Commit
f07beb9
ยท
verified ยท
1 Parent(s): 11f6819

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +7 -0
  2. README.md +35 -0
  3. bot.js +981 -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,981 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• FORMATTERS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
141
+ function fmtList(map, sortKey, emoji, unit, n = 10) {
142
+ const items = Object.values(map).sort((a, b) => (b[sortKey] || 0) - (a[sortKey] || 0)).slice(0, n);
143
+ if (!items.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุจูŠุงู†ุงุช ุจุนุฏ';
144
+ return items.map((x, i) => {
145
+ const m = medals[i] || `${i + 1}.`;
146
+ const rank = ranks[i] || `#${i + 1}`;
147
+ const u = x.username ? `\n โ”— <code>@${x.username}</code>` : '';
148
+ const val = formatK(x[sortKey] || 0);
149
+ return `${m} <b>ุงู„ู…ุฑูƒุฒ ${rank}</b>\n โ”œ ๐Ÿ‘ค <b>${esc(x.name)}</b>: ${val} ${unit}${u}`;
150
+ }).join('\n\n');
151
+ }
152
+
153
+ // ุชู†ุณูŠู‚ ุงู„ู…ุนู„ู‚ูŠู† ู…ุน ุนุฑุถ ุชุนู„ูŠู‚ุงุชู‡ู…
154
+ function fmtChatters(n = 10) {
155
+ const items = Object.values(chattersMap).sort((a, b) => (b.count || 0) - (a.count || 0)).slice(0, n);
156
+ if (!items.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุจูŠุงู†ุงุช ุจุนุฏ';
157
+ return items.map((x, i) => {
158
+ const m = medals[i] || `${i + 1}.`;
159
+ const rank = ranks[i] || `#${i + 1}`;
160
+ const u = x.username ? `\n โ”— <code>@${x.username}</code>` : '';
161
+ const lastMsgs = (x.messages || []).slice(-3).map(msg => ` ๐Ÿ’ฌ <i>"${esc(msg.substring(0, 50))}${msg.length > 50 ? '...' : ''}"</i>`).join('\n');
162
+ return `${m} <b>ุงู„ู…ุฑูƒุฒ ${rank}</b>\n โ”œ ๐Ÿ‘ค <b>${esc(x.name)}</b>: ${x.count} ุชุนู„ูŠู‚${u}\n${lastMsgs || ' ๐Ÿ’ฌ <i>ู„ุง ุชุนู„ูŠู‚ุงุช ู…ุญููˆุธุฉ</i>'}`;
163
+ }).join('\n\n');
164
+ }
165
+
166
+ // ุชู†ุณูŠู‚ ุงู„ู‡ุฏุงูŠุง ู…ุน ุฃุณู…ุงุก ุนุฑุจูŠุฉ
167
+ function fmtGifters(n = 10) {
168
+ const items = Object.values(giftersMap).sort((a, b) => (b.coins || 0) - (a.coins || 0)).slice(0, n);
169
+ if (!items.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุจูŠุงู†ุงุช ุจุนุฏ';
170
+ return items.map((x, i) => {
171
+ const m = medals[i] || `${i + 1}.`;
172
+ const rank = ranks[i] || `#${i + 1}`;
173
+ const u = x.username ? `\n โ”— <code>@${x.username}</code>` : '';
174
+ const giftNames = (x.gifts || []).slice(-3).map(g => getArabicGiftName(g)).join(' โ€ข ');
175
+ return `${m} <b>ุงู„ู…ุฑูƒุฒ ${rank}</b>\n โ”œ ๐Ÿ‘ค <b>${esc(x.name)}</b>: ${formatK(x.coins)} ๐Ÿ’Ž (${x.count} ู‡ุฏูŠุฉ)${u}\n โ”” ุขุฎุฑ ุงู„ู‡ุฏุงูŠุง: ${giftNames || 'ุบูŠุฑ ู…ุญุฏุฏ'}`;
176
+ }).join('\n\n');
177
+ }
178
+
179
+ // ุชู†ุณูŠู‚ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ
180
+ function fmtEnvelopes(n = 10) {
181
+ if (!envelopeWinners.length) return ' โณ ู„ุง ูŠูˆุฌุฏ ุตู†ุงุฏูŠู‚ ุฃูˆ ุญู‚ุงุฆุจ ุจุนุฏ';
182
+ return envelopeWinners.slice(-n).reverse().map((env, i) => {
183
+ const typeIcon = env.type === 'coinbag' ? '๐Ÿ’ฐ' : '๐Ÿ“ฆ';
184
+ const typeName = env.type === 'coinbag' ? 'ุญู‚ูŠุจุฉ ุนู…ู„ุงุช' : 'ุตู†ุฏูˆู‚ ูƒู†ุฒ';
185
+ const winList = (env.winners || []).map((w, wi) =>
186
+ ` ${wi + 1}. ๐Ÿ‘ค <b>${esc(w.name)}</b> ${w.username ? `<code>@${w.username}</code>` : ''} โ†’ ๐Ÿช™ ${formatK(w.coins)} ุนู…ู„ุฉ`
187
+ ).join('\n') || ' โณ ู„ู… ูŠุธู‡ุฑ ุงู„ูุงุฆุฒูŠู† ุจุนุฏ';
188
+ 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}`;
189
+ }).join('\n\n');
190
+ }
191
+
192
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• TELEGRAM โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
193
+ async function sendTg(text, silent = false, buttons = null, chatId = null) {
194
+ const targetChatId = chatId || CONFIG.TELEGRAM_CHAT_ID;
195
+ if (!CONFIG.TELEGRAM_TOKEN || !targetChatId) return null;
196
+ const urls = [];
197
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
198
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
199
+ for (const base of urls) {
200
+ try {
201
+ const p = { chat_id: targetChatId, text, parse_mode: 'HTML', disable_notification: silent, disable_web_page_preview: true };
202
+ if (buttons) p.reply_markup = { inline_keyboard: buttons };
203
+ const r = await axios.post(`${base}/sendMessage`, p, { timeout: 15000 });
204
+ if (r.data?.ok) return r.data;
205
+ } catch (e) {}
206
+ }
207
+ return null;
208
+ }
209
+
210
+ async function deleteTgMsg(chatId, msgId) {
211
+ if (!CONFIG.TELEGRAM_TOKEN || !chatId || !msgId) return;
212
+ const urls = [];
213
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
214
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
215
+ for (const base of urls) {
216
+ try {
217
+ await axios.post(`${base}/deleteMessage`, { chat_id: chatId, message_id: msgId }, { timeout: 10000 });
218
+ return;
219
+ } catch (e) {}
220
+ }
221
+ }
222
+
223
+ async function answerCallback(callbackId, text = '') {
224
+ const urls = [];
225
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
226
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
227
+ for (const base of urls) {
228
+ try {
229
+ await axios.post(`${base}/answerCallbackQuery`, { callback_query_id: callbackId, text, show_alert: !!text }, { timeout: 10000 });
230
+ return;
231
+ } catch (e) {}
232
+ }
233
+ }
234
+
235
+ // ุฅุฑุณุงู„ ู„ู„ู‚ู†ุงุชูŠู†
236
+ async function sendBoth(text, silent = false, buttons = null) {
237
+ const result = await sendTg(text, silent, buttons);
238
+ if (CONFIG.TELEGRAM_CHAT_ID_2) {
239
+ sendTg(text, silent, buttons, CONFIG.TELEGRAM_CHAT_ID_2).catch(() => {});
240
+ }
241
+ return result;
242
+ }
243
+
244
+ // ุฅุฑุณุงู„ ู…ุน ุญุฐู ุงู„ุณุงุจู‚
245
+ async function sendAndReplace(text, silent, buttons, type) {
246
+ // ุญุฐู ุงู„ุฑุณุงู„ุฉ ุงู„ุณุงุจู‚ุฉ ู…ู† ู†ูุณ ุงู„ู†ูˆุน
247
+ if (type === 'menu' && lastMenuMsgId) {
248
+ await deleteTgMsg(CONFIG.TELEGRAM_CHAT_ID, lastMenuMsgId);
249
+ lastMenuMsgId = null;
250
+ } else if (type === 'report' && lastReportMsgId) {
251
+ await deleteTgMsg(CONFIG.TELEGRAM_CHAT_ID, lastReportMsgId);
252
+ lastReportMsgId = null;
253
+ } else if (type === 'detail') {
254
+ for (const mid of lastDetailMsgIds) {
255
+ await deleteTgMsg(CONFIG.TELEGRAM_CHAT_ID, mid);
256
+ }
257
+ lastDetailMsgIds = [];
258
+ }
259
+
260
+ const result = await sendTg(text, silent, buttons);
261
+ if (result?.result?.message_id) {
262
+ if (type === 'menu') lastMenuMsgId = result.result.message_id;
263
+ else if (type === 'report') lastReportMsgId = result.result.message_id;
264
+ else if (type === 'detail') lastDetailMsgIds.push(result.result.message_id);
265
+ }
266
+
267
+ // ุฅุฑุณุงู„ ู„ู„ู‚ู†ุงุฉ ุงู„ุซุงู†ูŠุฉ
268
+ if (CONFIG.TELEGRAM_CHAT_ID_2) {
269
+ sendTg(text, silent, buttons, CONFIG.TELEGRAM_CHAT_ID_2).catch(() => {});
270
+ }
271
+ return result;
272
+ }
273
+
274
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• TEXT COMMANDS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
275
+ async function handleTextCommand(msg) {
276
+ const text = (msg.text || '').trim();
277
+ const chatId = String(msg.chat?.id || '');
278
+
279
+ // ูู‚ุท ุงู„ู…ุดุฑู
280
+ if (chatId !== CONFIG.TELEGRAM_CHAT_ID) return;
281
+
282
+ // ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน: /change username ุฃูˆ /ุบูŠุฑ username
283
+ if (text.startsWith('/change') || text.startsWith('/ุบูŠุฑ')) {
284
+ const parts = text.split(/\s+/);
285
+ const newUser = parts[1]?.replace('@', '').trim();
286
+ if (newUser) {
287
+ const oldUser = CONFIG.TIKTOK_USERNAME;
288
+ CONFIG.TIKTOK_USERNAME = newUser;
289
+
290
+ // ูุตู„ ุงู„ุงุชุตุงู„ ุงู„ุญุงู„ูŠ
291
+ if (tiktokConnection) {
292
+ try { tiktokConnection.disconnect(); } catch (e) {}
293
+ }
294
+ isConnected = false;
295
+
296
+ await sendTg(
297
+ `๐Ÿ”„ <b>ุชู… ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน!</b>\n` +
298
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
299
+ `โŒ ุงู„ุณุงุจู‚: <code>@${oldUser}</code>\n` +
300
+ `โœ… ุงู„ุฌุฏูŠุฏ: <code>@${newUser}</code>\n\n` +
301
+ `โณ ุฌุงุฑูŠ ุงู„ุงุชุตุงู„ ุจุงู„ุจุซ ุงู„ุฌุฏูŠุฏ...`
302
+ );
303
+
304
+ setTimeout(startBot, 3000);
305
+ } else {
306
+ await sendTg(`โŒ ุงุณุชุฎุฏู…: <code>/change username</code>\nุฃูˆ: <code>/ุบูŠุฑ username</code>`);
307
+ }
308
+ return;
309
+ }
310
+
311
+ // ุชุนูŠูŠู† ู‚ู†ุงุฉ ุซุงู†ูŠุฉ: /channel2 CHAT_ID ุฃูˆ /ู‚ู†ุงุฉ CHAT_ID
312
+ if (text.startsWith('/channel2') || text.startsWith('/ู‚ู†ุงุฉ')) {
313
+ const parts = text.split(/\s+/);
314
+ const newChannelId = parts[1]?.trim();
315
+ if (newChannelId) {
316
+ CONFIG.TELEGRAM_CHAT_ID_2 = newChannelId;
317
+ await sendTg(
318
+ `๐Ÿ“ข <b>ุชู… ุชุนูŠูŠู† ุงู„ู‚ู†ุงุฉ ุงู„ุซุงู†ูŠุฉ!</b>\n` +
319
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
320
+ `โœ… ู…ุนุฑู ุงู„ู‚ู†ุงุฉ: <code>${newChannelId}</code>\n` +
321
+ `๐Ÿ“ค ุณูŠุชู… ุฅุฑุณุงู„ ุฌู…ูŠุน ุงู„ุชู‚ุงุฑูŠุฑ ู„ู‡ุฐู‡ ุงู„ู‚ู†ุงุฉ ุฃูŠุถุงู‹`
322
+ );
323
+ } else {
324
+ await sendTg(`โŒ ุงุณุชุฎุฏู…: <code>/channel2 CHAT_ID</code>\nุฃูˆ: <code>/ู‚ู†ุงุฉ CHAT_ID</code>`);
325
+ }
326
+ return;
327
+ }
328
+
329
+ // ุงู„ุญุงู„ุฉ: /status ุฃูˆ /ุญุงู„ุฉ
330
+ if (text === '/status' || text === '/ุญุงู„ุฉ') {
331
+ await sendTg(
332
+ `๐Ÿ“ก <b>ุญุงู„ุฉ ุงู„ุจูˆุช</b>\n` +
333
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
334
+ `๐Ÿ‘ค ุงู„ู…ุฐูŠุน: <code>@${CONFIG.TIKTOK_USERNAME}</code>\n` +
335
+ `${isConnected ? '๐ŸŸข ู…ุชุตู„' : '๐Ÿ”ด ุบูŠุฑ ู…ุชุตู„'}\n` +
336
+ `โฑ ุงู„ู…ุฏุฉ: ${dur(startTime)}\n` +
337
+ `๐Ÿ“ข ุงู„ู‚ู†ุงุฉ ุง๏ฟฝ๏ฟฝุซุงู†ูŠุฉ: ${CONFIG.TELEGRAM_CHAT_ID_2 ? `<code>${CONFIG.TELEGRAM_CHAT_ID_2}</code>` : 'ุบูŠุฑ ู…ุนูŠู‘ู†ุฉ'}\n\n` +
338
+ `<b>ุงู„ุฃูˆุงู…ุฑ ุงู„ู…ุชุงุญุฉ:</b>\n` +
339
+ `โ€ข <code>/change username</code> - ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน\n` +
340
+ `โ€ข <code>/channel2 CHAT_ID</code> - ุชุนูŠูŠู† ู‚ู†ุงุฉ ุซุงู†ูŠุฉ\n` +
341
+ `โ€ข <code>/status</code> - ุญุงู„ุฉ ุงู„ุจูˆุช\n` +
342
+ `โ€ข <code>/clear</code> - ู…ุณุญ ุงู„ุฅุญุตุงุฆูŠุงุช`
343
+ );
344
+ return;
345
+ }
346
+
347
+ // ู…ุณุญ ุงู„ุฅุญุตุงุฆูŠุงุช: /clear ุฃูˆ /ู…ุณุญ
348
+ if (text === '/clear' || text === '/ู…ุณุญ') {
349
+ clearStats();
350
+ await sendTg(`โœ… ุชู… ู…ุณุญ ุฌู…ูŠุน ุงู„ุฅุญุตุงุฆูŠุงุช`);
351
+ return;
352
+ }
353
+ }
354
+
355
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• CALLBACK HANDLER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
356
+ async function handleCallback(data) {
357
+ const cb = data.data;
358
+ const cbId = data.id;
359
+
360
+ switch (cb) {
361
+ case 'gifts':
362
+ await sendAndReplace(
363
+ `๐ŸŽ <b>โ”โ”โ”โ” ู„ูˆุญุฉ ุงู„ู‡ุฏุงูŠุง โ”โ”โ”โ”</b>\n` +
364
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
365
+ `๐Ÿ’Ž ุฅุฌู…ุงู„ูŠ ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` +
366
+ `๐ŸŽ ุนุฏุฏ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n\n` +
367
+ `โ”โ”โ” ๐Ÿ† ุชุฑุชูŠุจ ุงู„ุฏุงุนู…ูŠู† โ”โ”โ”\n\n${fmtGifters(10)}`,
368
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
369
+ );
370
+ break;
371
+
372
+ case 'followers':
373
+ await sendAndReplace(
374
+ `โž• <b>โ”โ”โ”โ” ุงู„ู…ุชุงุจุนูŠู† ุงู„ุฌุฏุฏ โ”โ”โ”โ”</b>\n` +
375
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
376
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${totalFollows}</b> ู…ุชุงุจุน ุฌุฏูŠุฏ\n\n` +
377
+ `โ”โ”โ” ๐Ÿ‘ฅ ุขุฎุฑ ุงู„ู…ุชุงุจุนูŠู† โ”โ”โ”\n\n${fmtList(followersMap, 'time', 'โž•', '')}`,
378
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
379
+ );
380
+ break;
381
+
382
+ case 'likes':
383
+ await sendAndReplace(
384
+ `โค๏ธ <b>โ”โ”โ”โ” ุงู„ุฅุนุฌุงุจุงุช โ”โ”โ”โ”</b>\n` +
385
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
386
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${formatK(totalLikes)}</b> ุฅุนุฌุงุจ\n\n` +
387
+ `โ”โ”โ” ๐Ÿ”ฅ ุฃูƒุซุฑ ุงู„ู…ุนุฌุจูŠู† โ”โ”โ”\n\n${fmtList(likersMap, 'count', 'โค๏ธ', 'โค๏ธ')}`,
388
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
389
+ );
390
+ break;
391
+
392
+ case 'chatters':
393
+ await sendAndReplace(
394
+ `๐Ÿ’ฌ <b>โ”โ”โ”โ” ุงู„ุชุนู„ูŠู‚ุงุช โ”โ”โ”โ”</b>\n` +
395
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
396
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${formatK(totalComments)}</b> ุชุนู„ูŠู‚\n\n` +
397
+ `โ”โ”โ” ๐Ÿ—ฃ๏ธ ุฃู†ุดุท ุงู„ู…ุนู„ู‚ูŠู† โ”โ”โ”\n\n${fmtChatters(10)}`,
398
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
399
+ );
400
+ break;
401
+
402
+ case 'shares':
403
+ await sendAndReplace(
404
+ `โ†ช๏ธ <b>โ”โ”โ”โ” ุงู„ู…ุดุงุฑูƒุงุช โ”โ”โ”โ”</b>\n` +
405
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
406
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${totalShares}</b> ู…ุดุงุฑูƒุฉ\n\n` +
407
+ `โ”โ”โ” ๐Ÿ”„ ุฃูƒุซุฑ ุงู„ู…ุดุงุฑูƒูŠู† โ”โ”โ”\n\n${fmtList(sharersMap, 'count', 'โ†ช๏ธ', 'โ†ช๏ธ')}`,
408
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
409
+ );
410
+ break;
411
+
412
+ case 'envelopes':
413
+ await sendAndReplace(
414
+ `๐Ÿ“ฆ๐Ÿ’ฐ <b>โ”โ”โ”โ” ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ โ”โ”โ”โ”</b>\n` +
415
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
416
+ `๐Ÿ“ฆ ุฅุฌู…ุงู„ูŠ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n\n` +
417
+ `โ”โ”โ” ๐Ÿ† ุขุฎุฑ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ โ”โ”โ”\n\n${fmtEnvelopes(10)}`,
418
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
419
+ );
420
+ break;
421
+
422
+ case 'questions':
423
+ const qList = questionsArr.slice(-10).reverse().map((q, i) =>
424
+ `${i + 1}. <b>${esc(q.name)}</b>\n โ“ <i>"${esc(q.text)}"</i>`
425
+ ).join('\n\n') || ' ู„ุง ูŠูˆุฌุฏ ุฃุณุฆู„ุฉ';
426
+ await sendAndReplace(
427
+ `โ“ <b>โ”โ”โ”โ” ุงู„ุฃุณุฆู„ุฉ โ”โ”โ”โ”</b>\n` +
428
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
429
+ `๐Ÿ“Š ุงู„ุฅุฌู…ุงู„ูŠ: <b>${totalQuestions}</b> ุณุคุงู„\n\n${qList}`,
430
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
431
+ );
432
+ break;
433
+
434
+ case 'top_active':
435
+ const activeMap = {};
436
+ for (const [uid, g] of Object.entries(giftersMap)) {
437
+ if (!activeMap[uid]) activeMap[uid] = { name: g.name, username: g.username, score: 0 };
438
+ activeMap[uid].score += (g.coins || 0);
439
+ }
440
+ for (const [uid, c] of Object.entries(chattersMap)) {
441
+ if (!activeMap[uid]) activeMap[uid] = { name: c.name, username: c.username, score: 0 };
442
+ activeMap[uid].score += (c.count || 0) * 5;
443
+ }
444
+ for (const [uid, l] of Object.entries(likersMap)) {
445
+ if (!activeMap[uid]) activeMap[uid] = { name: l.name, username: l.username, score: 0 };
446
+ activeMap[uid].score += (l.count || 0);
447
+ }
448
+ for (const [uid, s] of Object.entries(sharersMap)) {
449
+ if (!activeMap[uid]) activeMap[uid] = { name: s.name, username: s.username, score: 0 };
450
+ activeMap[uid].score += (s.count || 0) * 20;
451
+ }
452
+ await sendAndReplace(
453
+ `๐Ÿ‘‘ <b>โ”โ”โ”โ” ุฃูƒุซุฑ ุงู„ู…ุชูุงุนู„ูŠู† โ”โ”โ”โ”</b>\n` +
454
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
455
+ `<i>๐Ÿงฎ ุงู„ู†ู‚ุงุท = ู…ุงุณุงุช + (ุชุนู„ูŠู‚ุงุชร—5) + (ู„ุงูŠูƒุงุช) + (ู…ุดุงุฑูƒุงุชร—20)</i>\n\n` +
456
+ `${fmtList(activeMap, 'score', '๐Ÿ‘‘', 'ู†ู‚ุทุฉ')}`,
457
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
458
+ );
459
+ break;
460
+
461
+ case 'stats':
462
+ const avgV = maxViewers > 0 ? Math.round((currentViewers + maxViewers) / 2) : currentViewers;
463
+ await sendAndReplace(
464
+ `๐Ÿ“ˆ <b>โ”โ”โ”โ” ุฅุญุตุงุฆูŠุงุช ู…ูุตู„ุฉ โ”โ”โ”โ”</b>\n` +
465
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
466
+ `โฑ ุงู„ู…ุฏุฉ: <b>${dur(startTime)}</b>\n` +
467
+ `๐Ÿ“… ${getDate()}\n\n` +
468
+ `โ”โ”โ” ๐Ÿ‘ ุงู„ู…ุดุงู‡ุฏูŠู† โ”โ”โ”\n` +
469
+ `ุงู„ุญุงู„ูŠูŠู†: <b>${formatK(currentViewers)}</b>\n` +
470
+ `ุงู„ุฃุนู„ู‰: <b>${formatK(maxViewers)}</b>\n` +
471
+ `ุงู„ู…ุชูˆุณุท: ~<b>${formatK(avgV)}</b>\n\n` +
472
+ `โ”โ”โ” ๐Ÿ“Š ุงู„ุฃุฑู‚ุงู… โ”โ”โ”\n` +
473
+ `๐Ÿ’Ž ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` +
474
+ `๐ŸŽ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n` +
475
+ `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n` +
476
+ `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช: <b>${totalComments}</b>\n` +
477
+ `โž• ุงู„ู…ุชุงุจุนูŠู†: <b>${totalFollows}</b>\n` +
478
+ `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช: <b>${totalShares}</b>\n` +
479
+ `โญ ุณูˆุจุฑ ูุงู†: <b>${totalSuperFans}</b>\n` +
480
+ `๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n` +
481
+ `โ“ ุงู„ุฃุณุฆู„ุฉ: <b>${totalQuestions}</b>\n` +
482
+ `๐Ÿ˜€ ุงู„ุฅูŠู…ูˆุช: <b>${totalEmotes}</b>`,
483
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
484
+ );
485
+ break;
486
+
487
+ case 'pk_status':
488
+ if (pkActive) {
489
+ const pkG = Object.values(pkInfo.pkGifts).sort((a, b) => b.coins - a.coins).slice(0, 5)
490
+ .map((g, i) => `${medals[i]} <b>${esc(g.name)}</b>: ${formatK(g.coins)} ๐Ÿ’Ž`).join('\n') || 'ู„ุง ูŠูˆุฌุฏ';
491
+ await sendAndReplace(
492
+ `โš”๏ธ <b>โ”โ”โ”โ” ุญุงู„ุฉ PK โ”โ”โ”โ”</b>\n` +
493
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
494
+ `๐Ÿ’Ž ุงู„ู†ุชูŠุฌุฉ: <b>${formatK(pkInfo.ourScore)}</b>\n` +
495
+ `โฑ ุงู„ู…ุฏุฉ: ${dur(pkInfo.startTime)}\n\n` +
496
+ `๐Ÿ† ุงู„ุฏุงุนู…ูŠู†:\n${pkG}`,
497
+ true, [[{ text: '๐Ÿ”™ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฑุฆูŠุณูŠุฉ', callback_data: 'menu' }]], 'detail'
498
+ );
499
+ } else {
500
+ await answerCallback(cbId, 'โš”๏ธ ู„ุง ูŠูˆุฌุฏ ุฌูˆู„ุฉ PK ู†ุดุทุฉ');
501
+ return;
502
+ }
503
+ break;
504
+
505
+ case 'menu':
506
+ await sendAndReplace(
507
+ `๐Ÿ“ก <b>โ”โ”โ”โ” ู„ูˆุญุฉ ุงู„ุชุญูƒู… โ”โ”โ”โ”</b>\n` +
508
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
509
+ `๐Ÿ‘ค @${CONFIG.TIKTOK_USERNAME}\n` +
510
+ `${isConnected ? `๐ŸŸข ู…ุชุตู„ โ€ข โฑ ${dur(startTime)}` : '๐Ÿ”ด ุบูŠุฑ ู…ุชุตู„'}\n` +
511
+ `๐Ÿ‘ ${formatK(currentViewers)} ู…ุดุงู‡ุฏ โ€ข ๐Ÿ’Ž ${formatK(totalDiamonds)} ู…ุงุณุฉ\n\n` +
512
+ `<i>๐Ÿ“Œ ุงุถุบุท ุฒุฑ ู„ุนุฑุถ ุงู„ุชูุงุตูŠู„ (ุงู„ุฑุณุงู„ุฉ ุงู„ุณุงุจู‚ุฉ ุชูุญุฐู ุชู„ู‚ุงุฆูŠุงู‹)</i>`,
513
+ true,
514
+ [
515
+ [{ text: `๐ŸŽ ุงู„ู‡ุฏุงูŠุง (${totalGifts})`, callback_data: 'gifts' }, { text: `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช (${formatK(totalLikes)})`, callback_data: 'likes' }],
516
+ [{ text: `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช (${totalComments})`, callback_data: 'chatters' }, { text: `โž• ุงู„ู…ุชุงุจุนูŠู† (${totalFollows})`, callback_data: 'followers' }],
517
+ [{ text: `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช (${totalShares})`, callback_data: 'shares' }, { text: `โ“ ุงู„ุฃุณุฆู„ุฉ (${totalQuestions})`, callback_data: 'questions' }],
518
+ [{ text: `๐Ÿ“ฆ๐Ÿ’ฐ ุงู„ุตู†ุงุฏูŠู‚ (${totalEnvelopes})`, callback_data: 'envelopes' }],
519
+ [{ text: '๐Ÿ‘‘ ุฃูƒุซุฑ ุงู„ู…ุชูุงุนู„ูŠู†', callback_data: 'top_active' }],
520
+ [{ text: '๐Ÿ“ˆ ุฅุญุตุงุฆูŠุงุช ู…ูุตู„ุฉ', callback_data: 'stats' }, { text: 'โš”๏ธ ุญุงู„ุฉ PK', callback_data: 'pk_status' }],
521
+ [{ text: '๐Ÿ”ด ุฏุฎูˆู„ ุงู„ุจุซ', url: LIVE() }],
522
+ ],
523
+ 'menu'
524
+ );
525
+ break;
526
+ }
527
+ await answerCallback(cbId);
528
+ }
529
+
530
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• CALLBACK POLLING โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
531
+ async function pollCallbacks() {
532
+ let offset = 0;
533
+ const urls = [];
534
+ if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`);
535
+ urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`);
536
+ let idx = 0;
537
+
538
+ while (true) {
539
+ try {
540
+ const base = urls[idx];
541
+ const res = await axios.get(`${base}/getUpdates`, {
542
+ params: { offset, limit: 10, timeout: 30 }, timeout: 35000
543
+ });
544
+ const updates = res.data?.result || [];
545
+ for (const u of updates) {
546
+ offset = u.update_id + 1;
547
+ if (u.callback_query) await handleCallback(u.callback_query);
548
+ if (u.message?.text) await handleTextCommand(u.message);
549
+ }
550
+ idx = 0;
551
+ } catch (e) {
552
+ idx = (idx + 1) % urls.length;
553
+ await new Promise(r => setTimeout(r, idx === 0 ? 5000 : 2000));
554
+ }
555
+ }
556
+ }
557
+
558
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• FLUSH & CLEAR โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
559
+ function clearStats() {
560
+ // ุชู†ุธูŠู ุงู„ุฐุงูƒุฑุฉ
561
+ for (const uid of Object.keys(chattersMap)) {
562
+ if (chattersMap[uid].messages?.length > 30) {
563
+ chattersMap[uid].messages = chattersMap[uid].messages.slice(-30);
564
+ }
565
+ }
566
+ for (const uid of Object.keys(giftersMap)) {
567
+ if (giftersMap[uid].gifts?.length > 10) {
568
+ giftersMap[uid].gifts = giftersMap[uid].gifts.slice(-10);
569
+ }
570
+ }
571
+ if (envelopeWinners.length > 50) {
572
+ envelopeWinners = envelopeWinners.slice(-50);
573
+ }
574
+ if (questionsArr.length > 50) {
575
+ questionsArr = questionsArr.slice(-50);
576
+ }
577
+ }
578
+
579
+ // ุฅุฑุณุงู„ ุชู‚ุฑูŠุฑ ุดุงู…ู„
580
+ async function sendFullStats() {
581
+ if (!isConnected) return;
582
+
583
+ const avgV = maxViewers > 0 ? Math.round((currentViewers + maxViewers) / 2) : currentViewers;
584
+
585
+ let statsMsg = `๐Ÿ“Š๐Ÿ”ฅ <b>โ”โ”โ” ุชู‚ุฑูŠุฑ ุดุงู…ู„ โ”โ”โ”</b>\n`;
586
+ statsMsg += `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n`;
587
+ statsMsg += `๐Ÿ‘ค <b>${CONFIG.TIKTOK_USERNAME}</b> โ€ข <code>@${CONFIG.TIKTOK_USERNAME}</code>\n`;
588
+ statsMsg += `โฑ <b>${dur(startTime)}</b> โ€ข ๐Ÿ“… ${getDate()}\n\n`;
589
+
590
+ statsMsg += `โ”โ”โ” ๐Ÿ‘ ุงู„ู…ุดุงู‡ุฏูŠู† โ”โ”โ”\n`;
591
+ statsMsg += `ุงู„ุญุงู„ูŠูŠู†: <b>${formatK(currentViewers)}</b> | ุงู„ุฃุนู„ู‰: <b>${formatK(maxViewers)}</b> | ุงู„ู…ุชูˆุณุท: ~<b>${formatK(avgV)}</b>\n\n`;
592
+
593
+ statsMsg += `โ”โ”โ” ๐Ÿ“Š ุงู„ุฃุฑู‚ุงู… โ”โ”โ”\n`;
594
+ statsMsg += `๐Ÿ’Ž ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n`;
595
+ statsMsg += `๐ŸŽ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n`;
596
+ statsMsg += `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n`;
597
+ statsMsg += `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช: <b>${totalComments}</b>\n`;
598
+ statsMsg += `โž• ุงู„ู…ุชุงุจุนูŠู†: <b>${totalFollows}</b>\n`;
599
+ statsMsg += `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช: <b>${totalShares}</b>\n`;
600
+ statsMsg += `๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n\n`;
601
+
602
+ statsMsg += `โ”โ”โ” ๐Ÿ† ุฃูุถู„ ุงู„ุฏุงุนู…ูŠู† โ”โ”โ”\n\n${fmtGifters(5)}\n\n`;
603
+ statsMsg += `โ”โ”โ” ๐Ÿ’ฌ ุฃู†ุดุท ุงู„ู…ุนู„ู‚ูŠู† โ”โ”โ”\n\n${fmtChatters(5)}`;
604
+
605
+ await sendAndReplace(statsMsg, false, [
606
+ [{ text: `๐ŸŽ ุงู„ู‡ุฏุงูŠุง (${totalGifts})`, callback_data: 'gifts' }, { text: `โค๏ธ ุงู„ู„ุงูŠูƒุงุช (${formatK(totalLikes)})`, callback_data: 'likes' }],
607
+ [{ text: `๐Ÿ’ฌ ุงู„ู…ุนู„ู‚ูŠู† (${totalComments})`, callback_data: 'chatters' }, { text: `๐Ÿ‘‘ ุงู„ู…ุชูุงุนู„ูŠู†`, callback_data: 'top_active' }],
608
+ [{ text: '๐Ÿ“ฆ๐Ÿ’ฐ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ', callback_data: 'envelopes' }],
609
+ [{ text: '๐Ÿ“ˆ ุชูุงุตูŠู„ ูƒุงู…ู„ุฉ', callback_data: 'stats' }],
610
+ [{ text: '๐Ÿ”ด ุฏุฎูˆู„ ุงู„ุจุซ', url: LIVE() }],
611
+ ], 'report');
612
+ }
613
+
614
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• REPORTS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
615
+ function startReports() {
616
+ if (reportInterval) clearInterval(reportInterval);
617
+ reportInterval = setInterval(() => {
618
+ if (!isConnected) return;
619
+ sendFullStats();
620
+ }, CONFIG.REPORT_INTERVAL * 60000);
621
+ }
622
+
623
+ // ุชู†ุธูŠู ูƒู„ 50 ุฏู‚ูŠู‚ุฉ
624
+ function startFlushTimer() {
625
+ if (flushInterval) clearInterval(flushInterval);
626
+ flushInterval = setInterval(() => {
627
+ clearStats();
628
+ console.log('[Flush] โœ… Memory cleaned');
629
+ // ุฅุฑุณุงู„ ุชู‚ุฑูŠุฑ ุญุชู‰ ู„ูˆ ู„ู… ูŠูุถุบุท ุฒุฑ
630
+ if (isConnected) {
631
+ sendFullStats();
632
+ }
633
+ }, 50 * 60000);
634
+ }
635
+
636
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• HTTP SERVER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
637
+ const server = http.createServer((req, res) => {
638
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
639
+ 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>
640
+ <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>
641
+ <body><div class="w"><div class="h"><h1>๐Ÿ“ก TikTok Radar</h1><p style="opacity:.7">v11.0 - ุงู„ู†ุณุฎุฉ ุงู„ู…ุญุณู‘ู†ุฉ</p></div>
642
+ <div class="s">${isConnected?'๐ŸŸข ู…ุชุตู„':'๐Ÿ”ด ู…ู†ุชุธุฑ'} โ€ข @${CONFIG.TIKTOK_USERNAME}</div>
643
+ ${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>
644
+ <div class="env"><b>๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚ ูˆุงู„ุญู‚ุงุฆุจ:</b> ${totalEnvelopes}<br><b>โฑ ุงู„ู…ุฏุฉ:</b> ${dur(startTime)}</div>`:''}
645
+ <div style="margin-top:20px;text-align:center;font-size:12px;color:#666">
646
+ <b>ุงู„ุฃูˆุงู…ุฑ:</b><br>
647
+ /change username - ุชุบูŠูŠุฑ ุงู„ู…ุฐูŠุน<br>
648
+ /channel2 CHAT_ID - ู‚ู†ุงุฉ ุซุงู†ูŠุฉ<br>
649
+ /status - ุงู„ุญุงู„ุฉ
650
+ </div>
651
+ </div></body></html>`);
652
+ });
653
+
654
+ server.listen(PORT, '0.0.0.0', () => {
655
+ console.log(`\n๐ŸŽฏ TikTok Radar v11.0 | Port ${PORT} | @${CONFIG.TIKTOK_USERNAME}\n`);
656
+ pollCallbacks();
657
+ setTimeout(startBot, 2000);
658
+ });
659
+
660
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• MAIN BOT โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
661
+ async function startBot() {
662
+ console.log(`[Bot] ๐Ÿ”Ž @${CONFIG.TIKTOK_USERNAME}...`);
663
+ let TikTokLiveConnection, WebcastEvent, ControlEvent;
664
+ try {
665
+ const lib = require('tiktok-live-connector');
666
+ TikTokLiveConnection = lib.TikTokLiveConnection;
667
+ WebcastEvent = lib.WebcastEvent;
668
+ ControlEvent = lib.ControlEvent;
669
+ } catch (e) { console.error('[Bot] โŒ', e.message); setTimeout(startBot, 30000); return; }
670
+
671
+ try {
672
+ const opts = { processInitialData: true, enableExtendedGiftInfo: true, fetchRoomInfoOnConnect: true };
673
+ if (CONFIG.SIGN_API_KEY) opts.signApiKey = CONFIG.SIGN_API_KEY;
674
+ if (CONFIG.SESSION_ID && CONFIG.SESSION_ID.length > 10) {
675
+ opts.session = { cookie: { type: 'cookie', value: { sessionId: CONFIG.SESSION_ID, ttTargetIdc: CONFIG.TT_TARGET_IDC } } };
676
+ opts.authenticateWs = true;
677
+ }
678
+ tiktokConnection = new TikTokLiveConnection(CONFIG.TIKTOK_USERNAME, opts);
679
+
680
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โœ… CONNECTED โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
681
+ tiktokConnection.on(ControlEvent.CONNECTED, (state) => {
682
+ isConnected = true; startTime = new Date();
683
+ totalGifts=0;totalDiamonds=0;totalLikes=0;totalComments=0;totalFollows=0;
684
+ totalShares=0;totalSuperFans=0;totalQuestions=0;totalEnvelopes=0;totalEmotes=0;
685
+ maxViewers=0;currentViewers=0;
686
+ giftersMap={};followersMap={};chattersMap={};sharersMap={};likersMap={};
687
+ envelopeWinners=[];
688
+ questionsArr=[];pinnedMessages=[];pkActive=false;
689
+ roomTitle = state.roomInfo?.title || '';
690
+
691
+ console.log(`[Bot] โœ… Room: ${state.roomId}`);
692
+ sendBoth(
693
+ `๐Ÿ“กโœจ <b>ุงู„ุจุซ ุงู„ู…ุจุงุดุฑ ุจุฏุฃ!</b>\n` +
694
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
695
+ `๐Ÿ‘ค <b>${CONFIG.TIKTOK_USERNAME}</b>\n` +
696
+ `๐Ÿ”— <code>@${CONFIG.TIKTOK_USERNAME}</code>\n` +
697
+ (roomTitle ? `๐Ÿ“ ${esc(roomTitle)}\n` : '') +
698
+ `โฐ ${getTime()} โ€ข ๐Ÿ“… ${getDate()}\n\n` +
699
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n` +
700
+ `๐ŸŽ‰ <b>ุงู„ุจุซ ุจุฏุฃ! ุงู†ุถู… ุงู„ุขู†!</b>`,
701
+ false,
702
+ [
703
+ [{ text: '๐Ÿ”ด ุฏุฎูˆู„ ุงู„ุจุซ ุงู„ู…ุจุงุดุฑ', url: LIVE() }],
704
+ [{ text: '๐Ÿ“Š ู„ูˆุญุฉ ุงู„ุชุญูƒู…', callback_data: 'menu' }]
705
+ ]
706
+ );
707
+ startReports();
708
+ startFlushTimer();
709
+ });
710
+
711
+ tiktokConnection.on(ControlEvent.DISCONNECTED, () => {
712
+ isConnected = false;
713
+ if (reportInterval) clearInterval(reportInterval);
714
+ if (flushInterval) clearInterval(flushInterval);
715
+ scheduleReconnect(30000);
716
+ });
717
+
718
+ tiktokConnection.on(ControlEvent.ERROR, (err) => console.error('[Bot] โš ๏ธ', err?.info || err?.message || err));
719
+
720
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ”ด STREAM END โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
721
+ tiktokConnection.on(WebcastEvent.STREAM_END, () => {
722
+ isConnected = false;
723
+ if (reportInterval) clearInterval(reportInterval);
724
+ if (flushInterval) clearInterval(flushInterval);
725
+ sendBoth(
726
+ `๐Ÿ”ด <b>ุงู†ุชู‡ู‰ ุงู„ุจุซ!</b>\n` +
727
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
728
+ `๐Ÿ‘ค <b>${CONFIG.TIKTOK_USERNAME}</b>\n` +
729
+ `โฑ ุงู„ู…ุฏุฉ: <b>${dur(startTime)}</b>\n` +
730
+ `๐Ÿ“… ${getDate()}\n\n` +
731
+ `โ”โ”โ” ๐Ÿ“Š ุงู„ู…ู„ุฎุต ุงู„ู†ู‡ุงุฆูŠ โ”โ”โ”\n` +
732
+ `๐Ÿ’Ž ุงู„ู…ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` +
733
+ `๐ŸŽ ุงู„ู‡ุฏุงูŠุง: <b>${totalGifts}</b>\n` +
734
+ `โค๏ธ ุงู„ุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n` +
735
+ `๐Ÿ’ฌ ุงู„ุชุนู„ูŠู‚ุงุช: <b>${totalComments}</b>\n` +
736
+ `โž• ุงู„ู…ุชุงุจุนูŠู†: <b>${totalFollows}</b>\n` +
737
+ `โ†ช๏ธ ุงู„ู…ุดุงุฑูƒุงุช: <b>${totalShares}</b>\n` +
738
+ `๐Ÿ“ฆ ุงู„ุตู†ุงุฏูŠู‚: <b>${totalEnvelopes}</b>\n\n` +
739
+ `โ”โ”โ” ๐Ÿ† ุฃูุถู„ ุงู„ุฏุงุนู…ูŠู† โ”โ”โ”\n\n${fmtGifters(5)}\n\n` +
740
+ `โ”โ”โ” ๐Ÿ’ฌ ุฃู†ุดุท ุงู„ู…ุนู„ู‚ูŠู† โ”โ”โ”\n\n${fmtChatters(5)}\n\n` +
741
+ `โœจ <b>ุดูƒุฑุงู‹ ู„ู„ุฌู…ูŠุน!</b>`
742
+ );
743
+ scheduleReconnect(60000);
744
+ });
745
+
746
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ’ฌ CHAT โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
747
+ tiktokConnection.on(WebcastEvent.CHAT, (data) => {
748
+ totalComments++;
749
+ const uid = data.user?.userId || data.user?.uniqueId || 'x';
750
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
751
+ const uname = data.user?.uniqueId || '';
752
+ const comment = data.comment || '';
753
+ if (!chattersMap[uid]) chattersMap[uid] = { name, username: uname, count: 0, messages: [] };
754
+ chattersMap[uid].count++;
755
+ if (comment) {
756
+ chattersMap[uid].messages.push(comment);
757
+ if (chattersMap[uid].messages.length > 20) {
758
+ chattersMap[uid].messages = chattersMap[uid].messages.slice(-20);
759
+ }
760
+ }
761
+ });
762
+
763
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐ŸŽ GIFT โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
764
+ tiktokConnection.on(WebcastEvent.GIFT, (data) => {
765
+ const uid = data.user?.userId || data.user?.uniqueId || 'x';
766
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
767
+ const uname = data.user?.uniqueId || '';
768
+ const gn = data.giftName || data.extendedGiftInfo?.name || 'Gift';
769
+ const gnAr = getArabicGiftName(gn);
770
+ const gt = data.giftType ?? 0;
771
+ const rc = data.repeatCount ?? 1;
772
+ const re = data.repeatEnd ?? true;
773
+ let dc = data.diamondCount || data.extendedGiftInfo?.diamondCount || data.extendedGiftInfo?.diamond_count || data.gift?.diamond_count || data.giftDetails?.diamondCount || 0;
774
+ if (gt === 1 && re === false) return;
775
+ const cost = dc * rc;
776
+ totalGifts++; totalDiamonds += cost;
777
+ if (!giftersMap[uid]) giftersMap[uid] = { name, username: uname, coins: 0, count: 0, gifts: [] };
778
+ giftersMap[uid].coins += cost; giftersMap[uid].count++;
779
+ giftersMap[uid].gifts.push(gn);
780
+ if (giftersMap[uid].gifts.length > 10) {
781
+ giftersMap[uid].gifts = giftersMap[uid].gifts.slice(-10);
782
+ }
783
+ if (pkActive) {
784
+ if (!pkInfo.pkGifts[uid]) pkInfo.pkGifts[uid] = { name, username: uname, coins: 0 };
785
+ pkInfo.pkGifts[uid].coins += cost;
786
+ }
787
+ console.log(`[๐ŸŽ] ${name}: ${gnAr} = ${cost}๐Ÿ’Ž`);
788
+ });
789
+
790
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โค๏ธ LIKE โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
791
+ tiktokConnection.on(WebcastEvent.LIKE, (data) => {
792
+ const likes = data.likeCount || 1;
793
+ totalLikes += likes;
794
+ const uid = data.user?.userId || data.user?.uniqueId || 'x';
795
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
796
+ const uname = data.user?.uniqueId || '';
797
+ if (!likersMap[uid]) likersMap[uid] = { name, username: uname, count: 0 };
798
+ likersMap[uid].count += likes;
799
+ });
800
+
801
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โž• FOLLOW โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
802
+ tiktokConnection.on(WebcastEvent.FOLLOW, (data) => {
803
+ totalFollows++;
804
+ const uid = data.user?.userId || data.user?.uniqueId || Date.now();
805
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
806
+ const uname = data.user?.uniqueId || '';
807
+ followersMap[uid] = { name, username: uname, time: Date.now() };
808
+ });
809
+
810
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ†ช๏ธ SHARE โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
811
+ tiktokConnection.on(WebcastEvent.SHARE, (data) => {
812
+ totalShares++;
813
+ const uid = data.user?.uniqueId || 'x';
814
+ const name = data.user?.nickname || data.user?.uniqueId || '?';
815
+ if (!sharersMap[uid]) sharersMap[uid] = { name, username: uid, count: 0 };
816
+ sharersMap[uid].count++;
817
+ });
818
+
819
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ‘ VIEWERS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
820
+ tiktokConnection.on(WebcastEvent.ROOM_USER, (data) => {
821
+ currentViewers = data.viewerCount || 0;
822
+ if (currentViewers > maxViewers) maxViewers = currentViewers;
823
+ });
824
+
825
+ tiktokConnection.on(WebcastEvent.MEMBER, () => {});
826
+ tiktokConnection.on(WebcastEvent.EMOTE, () => { totalEmotes++; });
827
+
828
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“ฆ ENVELOPE - ุตู†ุฏูˆู‚ / ุญู‚ูŠุจุฉ ุนู…ู„ุงุช โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
829
+ tiktokConnection.on(WebcastEvent.ENVELOPE, (data) => {
830
+ totalEnvelopes++;
831
+ const env = data.envelopeInfo;
832
+ if (env) {
833
+ const senderName = env.sendUserName || '?';
834
+ const senderUsername = env.sendUserUniqueId || '';
835
+ const diamonds = env.diamondCount || 0;
836
+ const peopleCount = env.peopleCount || 0;
837
+
838
+ // ุชุญุฏูŠุฏ ุงู„ู†ูˆุน
839
+ const envType = (env.envelopeType === 2 || String(env.description || '').includes('ุญู‚ูŠุจุฉ') || String(env.description || '').includes('coin')) ? 'coinbag' : 'chest';
840
+ const typeIcon = envType === 'coinbag' ? '๐Ÿ’ฐ' : '๐Ÿ“ฆ';
841
+ const typeName = envType === 'coinbag' ? 'ุญู‚ูŠุจุฉ ุนู…ู„ุงุช' : 'ุตู†ุฏูˆู‚ ูƒู†ุฒ';
842
+
843
+ // ุงุณุชุฎุฑุงุฌ ุงู„ูุงุฆุฒูŠู†
844
+ const winners = [];
845
+ if (env.envelopeGrabUserList) {
846
+ for (const w of env.envelopeGrabUserList) {
847
+ winners.push({
848
+ name: w.nickname || w.uniqueId || '?',
849
+ username: w.uniqueId || '',
850
+ coins: w.diamondCount || w.coinCount || 0,
851
+ });
852
+ }
853
+ }
854
+
855
+ envelopeWinners.push({ type: envType, sender: senderName, senderUsername, diamonds, peopleCount, winners, time: new Date() });
856
+
857
+ let winnerText = '';
858
+ if (winners.length) {
859
+ winnerText = `\n\n๐Ÿ† <b>ุงู„ูุงุฆุฒูŠู†:</b>\n` + winners.map((w, i) =>
860
+ ` ${i + 1}. ๐Ÿ‘ค <b>${esc(w.name)}</b> ${w.username ? `<code>@${w.username}</code>` : ''}\n ๐Ÿช™ ุญุตู„ ุนู„ู‰: <b>${formatK(w.coins)}</b> ุนู…ู„ุฉ`
861
+ ).join('\n');
862
+ }
863
+
864
+ sendBoth(
865
+ `${typeIcon}โœจ <b>${typeName}!</b>\n` +
866
+ `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n` +
867
+ `๐Ÿ‘ค ุงู„ู…ุฑุณู„: <b>${esc(senderName)}</b> ${senderUsername ? `<code>@${senderUsername}</code>` : ''}\n` +
868
+ `๐Ÿ’Ž <b>${formatK(diamonds)}</b> ู…ุงุณุฉ โ€ข ๐Ÿ‘ฅ <b>${peopleCount}</b> ุดุฎุต` +
869
+ winnerText
870
+ );
871
+ }
872
+ });
873
+
874
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ“ QUESTION โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
875
+ try { tiktokConnection.on(WebcastEvent.QUESTION_NEW, (data) => {
876
+ totalQuestions++;
877
+ const q = data.details?.questionText || '';
878
+ const name = data.details?.user?.nickname || '?';
879
+ if (q) questionsArr.push({ name, text: q, time: Date.now() });
880
+ }); } catch (e) {}
881
+
882
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โญ SUPER FAN โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
883
+ try { tiktokConnection.on(WebcastEvent.SUPER_FAN, (data) => {
884
+ totalSuperFans++;
885
+ const msg = data.content?.defaultPattern || data.commonBarrageContent?.defaultPattern || '';
886
+ sendBoth(`โญ๐ŸŒŸ <b>ุณูˆุจุฑ ูุงู† ุฌุฏูŠุฏ!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n${esc(msg) || '๐Ÿ‘‘ ู…ุณุชุฎุฏู… ุฃุตุจุญ ุณูˆุจุฑ ูุงู†!'}`);
887
+ }); } catch (e) {}
888
+
889
+ try { tiktokConnection.on(WebcastEvent.SUPER_FAN_JOIN, () => {}); } catch (e) {}
890
+ try { tiktokConnection.on(WebcastEvent.SUPER_FAN_BOX, (data) => {
891
+ if (data.envelopeInfo) sendBoth(`โญ๐Ÿ“ฆ <b>ุตู†ุฏูˆู‚ ุณูˆุจุฑ ูุงู†!</b>`);
892
+ }); } catch (e) {}
893
+
894
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“Œ PIN โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
895
+ try { tiktokConnection.on(WebcastEvent.ROOM_PIN, (data) => {
896
+ const by = data.operator?.nickname || '?';
897
+ const chat = data.chatMessage?.comment || '';
898
+ if (chat) sendBoth(`๐Ÿ“Œ <b>ุฑุณุงู„ุฉ ู…ุซุจุชุฉ</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n๐Ÿ‘ค <b>${esc(by)}</b>\n๐Ÿ’ฌ <i>"${esc(chat)}"</i>`, true);
899
+ }); } catch (e) {}
900
+
901
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โš”๏ธ PK โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
902
+ tiktokConnection.on(WebcastEvent.LINK_MIC_BATTLE, (data) => {
903
+ pkActive = true;
904
+ pkInfo = { battleId: data.battleId || '', participantDetails: [], ourScore: 0, theirScore: 0, startTime: new Date(), pkGifts: {} };
905
+ const details = [];
906
+ for (const [k, info] of Object.entries(data.anchorInfo || {})) {
907
+ const u = info.user || info || {};
908
+ const did = u.displayId || u.uniqueId || '';
909
+ const nn = u.nickName || u.nickname || did || 'ู…ุฌู‡ูˆู„';
910
+ if (did || nn !== 'ู…ุฌู‡ูˆู„') details.push({ name: nn, username: did });
911
+ }
912
+ pkInfo.participantDetails = details;
913
+ const opp = details.find(p => p.username !== CONFIG.TIKTOK_USERNAME && p.name !== CONFIG.TIKTOK_USERNAME) || details[1] || null;
914
+
915
+ let msg = `โš”๏ธ๐Ÿ”ฅ <b>ุฌูˆู„ุฉ PK ุฌุฏูŠุฏุฉ!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n`;
916
+ msg += `๐Ÿ  <b>${esc(CONFIG.TIKTOK_USERNAME)}</b>\n <code>@${CONFIG.TIKTOK_USERNAME}</code>\n\n ๐Ÿ†š\n\n`;
917
+ if (opp) msg += `๐ŸฅŠ <b>${esc(opp.name)}</b>\n <code>@${opp.username || '?'}</code>\n\n`;
918
+ else msg += `๐ŸฅŠ โณ ุฌุงุฑูŠ ุงู„ุชุญู…ูŠู„...\n\n`;
919
+ msg += `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿš€ <b>ุงุฏุนู…ูˆุง ุงู„ุจุซ!</b>`;
920
+ sendBoth(msg, false, [
921
+ [{ text: '๐Ÿ”ด ุงุฏุฎู„ ูˆุงุฏุนู…!', url: LIVE() }],
922
+ [{ text: 'โš”๏ธ ู†ุชูŠุฌุฉ PK', callback_data: 'pk_status' }]
923
+ ]);
924
+ });
925
+
926
+ tiktokConnection.on(WebcastEvent.LINK_MIC_ARMIES, (data) => {
927
+ if (pkActive && data.totalDiamondCount) pkInfo.ourScore = data.totalDiamondCount;
928
+ });
929
+
930
+ try { tiktokConnection.on(WebcastEvent.LINK_MIC_BATTLE_PUNISH_FINISH, () => {
931
+ pkActive = false;
932
+ const pkG = Object.values(pkInfo.pkGifts).sort((a, b) => b.coins - a.coins).slice(0, 5)
933
+ .map((g, i) => `${medals[i]} <b>${esc(g.name)}</b>: ${formatK(g.coins)} ๐Ÿ’Ž`).join('\n') || 'ู„ุง ูŠูˆุฌุฏ';
934
+ sendBoth(`๐Ÿ† <b>ุงู†ุชู‡ุช PK!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n๐Ÿ’Ž <b>${formatK(pkInfo.ourScore)}</b> โ€ข โฑ ${dur(pkInfo.startTime)}\n\n๐Ÿ† ุงู„ุฏุงุนู…ูŠู†:\n${pkG}\n\nโœจ <b>ุดูƒุฑุงู‹ ู„ู„ุฌู…ูŠุน!</b>`);
935
+ }); } catch (e) {}
936
+
937
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐ŸŽฏ GOAL โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
938
+ try { tiktokConnection.on(WebcastEvent.GOAL_UPDATE, (data) => {
939
+ const d = data.goal?.description || '';
940
+ if (d) sendBoth(`๐ŸŽฏ <b>ุชุญุฏูŠุซ ุงู„ู‡ุฏู!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ“‹ ${esc(d)}`, true);
941
+ }); } catch (e) {}
942
+
943
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ—ณ๏ธ POLL โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
944
+ try { tiktokConnection.on(WebcastEvent.POLL_MESSAGE, (data) => {
945
+ const t = data.pollBasicInfo?.title || '';
946
+ if (t) sendBoth(`๐Ÿ—ณ๏ธ <b>ุชุตูˆูŠุช!</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ“‹ <b>${esc(t)}</b>`, true);
947
+ }); } catch (e) {}
948
+
949
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ›’ SHOPPING โ•โ•โ•โ•โ•โ•๏ฟฝ๏ฟฝ๏ฟฝโ•โ•โ•
950
+ try { tiktokConnection.on(WebcastEvent.OEC_LIVE_SHOPPING, (data) => {
951
+ const s = data.shopData;
952
+ if (s?.title) sendBoth(`๐Ÿ›’ <b>ู…ู†ุชุฌ!</b>\n๐Ÿ“ฆ ${esc(s.title)}${s.priceString ? `\n๐Ÿ’ฐ ${esc(s.priceString)}` : ''}`, true);
953
+ }); } catch (e) {}
954
+
955
+ try { tiktokConnection.on(WebcastEvent.RANK_UPDATE, () => {}); } catch (e) {}
956
+ try { tiktokConnection.on(WebcastEvent.RANK_TEXT, (data) => {
957
+ if (data.ownerIdxAfterUpdate && data.ownerIdxBeforeUpdate && data.ownerIdxAfterUpdate < data.ownerIdxBeforeUpdate)
958
+ sendBoth(`๐Ÿ†๐Ÿ“ˆ ุงุฑุชูุน ุงู„ุชุฑุชูŠุจ! #${data.ownerIdxBeforeUpdate} โ†’ #${data.ownerIdxAfterUpdate} ๐Ÿ”ฅ`, true);
959
+ }); } catch (e) {}
960
+ tiktokConnection.on(WebcastEvent.LIVE_INTRO, () => {});
961
+ try { tiktokConnection.on(WebcastEvent.ROOM_MESSAGE, () => {}); } catch (e) {}
962
+ try { tiktokConnection.on(WebcastEvent.CAPTION_MESSAGE, () => {}); } catch (e) {}
963
+
964
+ console.log('[Bot] ๐Ÿ”Œ Connecting...');
965
+ await tiktokConnection.connect();
966
+ } catch (err) {
967
+ console.error('[Bot] โŒ', err.message || err);
968
+ isConnected = false;
969
+ scheduleReconnect(60000);
970
+ }
971
+ }
972
+
973
+ function scheduleReconnect(d) {
974
+ if (reconnectTimer) clearTimeout(reconnectTimer);
975
+ console.log(`[Bot] ๐Ÿ”„ ${d / 1000}s...`);
976
+ reconnectTimer = setTimeout(() => { reconnectTimer = null; if (!isConnected) startBot(); }, d);
977
+ }
978
+
979
+ process.on('uncaughtException', e => console.error('[!]', e.message));
980
+ process.on('unhandledRejection', r => console.error('[!]', r));
981
+ 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
+ }