Download bot.js from Reooiq/Radar: direct link, hf CLI and curl.
- Browser
- Download file 40.4 kB
-
https://huggingface.co/spaces/Reooiq/Radar/resolve/main/bot.js
- Command line
-
hf download hf://spaces/Reooiq/Radar/bot.js
-
curl -L -o bot.js https://huggingface.co/spaces/Reooiq/Radar/resolve/main/bot.js
40.4 kB
| /** | |
| * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| * โ โ | |
| * โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโ โโโ โโโ โโโโโโโ โโโโโโ โ | |
| * โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโ โโโโ โโโโโโโโโโโโโโโโ โ | |
| * โ โโโ โโโโโโโโโโ โโโ โโโ โโโโโโโโโโ โโโโโโโโโโโโโโโโ โ | |
| * โ โโโ โโโโโโโโโโ โโโ โโโ โโโโโโโโโโ โโโโโโโโโโโโโโโโ โ | |
| * โ โโโ โโโโโโ โโโ โโโ โโโโโโโโโโโโ โโโ โโโ โโโโโโ โโโ โ | |
| * โ โโโ โโโโโโ โโโ โโโ โโโโโโโ โโโ โโโ โโโ โโโโโโ โโโ โ | |
| * โ โ | |
| * โ ๐ฏ TikTok Radar Bot v8.0 Premium ๐ฏ โ | |
| * โ Based on Official Documentation โ | |
| * โ https://github.com/zerodytrash/TikTok-Live-Connector โ | |
| * โ โ | |
| * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| */ | |
| const http = require('http'); | |
| const axios = require('axios'); | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ AUTHENTICATION SETUP | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| process.env.WHITELIST_AUTHENTICATED_SESSION_ID_HOST = 'tiktok.eulerstream.com'; | |
| const PORT = process.env.PORT || 7860; | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // โ๏ธ CONFIGURATION | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| const CONFIG = { | |
| TIKTOK_USERNAME: (process.env.TIKTOK_USERNAME || 'a200_89').trim(), | |
| SESSION_ID: (process.env.SESSION_ID || '').trim(), | |
| TT_TARGET_IDC: (process.env.TT_TARGET_IDC || 'alisg').trim(), | |
| TELEGRAM_TOKEN: (process.env.TELEGRAM_TOKEN || '').trim(), | |
| TELEGRAM_CHAT_ID: (process.env.TELEGRAM_CHAT_ID || '').trim(), | |
| PROXY_URL: (process.env.PROXY_URL || '').trim().replace(/\/$/, ''), | |
| REPORT_INTERVAL: parseInt(process.env.REPORT_INTERVAL || '10'), | |
| }; | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ STATE VARIABLES | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| let isConnected = false; | |
| let tiktokConnection = null; | |
| let totalGifts = 0; | |
| let totalDiamonds = 0; | |
| let totalLikes = 0; | |
| let totalComments = 0; | |
| let totalFollows = 0; | |
| let totalShares = 0; | |
| let maxViewers = 0; | |
| let currentViewers = 0; | |
| let startTime = null; | |
| let giftersMap = {}; | |
| let followersMap = {}; | |
| let reconnectTimer = null; | |
| let reportInterval = null; | |
| // โ๏ธ PK Battle State | |
| let pkActive = false; | |
| let pkInfo = { | |
| battleId: '', | |
| participants: [], | |
| participantDetails: [], | |
| ourScore: 0, | |
| theirScore: 0, | |
| startTime: null, | |
| pkGifts: {}, | |
| }; | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ HTTP SERVER | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| const server = http.createServer((req, res) => { | |
| res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); | |
| const topGiftersHtml = Object.values(giftersMap) | |
| .sort((a, b) => b.coins - a.coins) | |
| .slice(0, 5) | |
| .map((g, i) => `<div style="padding:5px;background:#1a1a2e;margin:3px;border-radius:5px"> | |
| ${['๐ฅ','๐ฅ','๐ฅ','๐ ','๐'][i]} ${g.name}: ${g.coins}๐ | |
| </div>`) | |
| .join('') || '<div style="color:#666">ูุง ููุฌุฏ ุฏุงุนู ูู ุจุนุฏ</div>'; | |
| res.end(` | |
| <!DOCTYPE html> | |
| <html dir="rtl"> | |
| <head> | |
| <title>๐ก TikTok Radar v8.0</title> | |
| <meta charset="UTF-8"> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #0a0a0a 100%); | |
| color: #fff; | |
| font-family: 'Segoe UI', Tahoma, sans-serif; | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { max-width: 600px; margin: 0 auto; } | |
| .header { | |
| text-align: center; | |
| padding: 30px; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border-radius: 20px; | |
| margin-bottom: 20px; | |
| box-shadow: 0 10px 40px rgba(102, 126, 234, 0.3); | |
| } | |
| .status { | |
| font-size: 28px; | |
| padding: 15px; | |
| background: ${isConnected ? 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)' : 'linear-gradient(135deg, #eb3349 0%, #f45c43 100%)'}; | |
| border-radius: 15px; | |
| margin: 20px 0; | |
| box-shadow: 0 5px 20px rgba(0,0,0,0.3); | |
| } | |
| .stats { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 10px; | |
| margin: 20px 0; | |
| } | |
| .stat { | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| padding: 15px; | |
| border-radius: 15px; | |
| text-align: center; | |
| border: 1px solid #333; | |
| } | |
| .stat-value { font-size: 24px; font-weight: bold; color: #667eea; } | |
| .stat-label { font-size: 12px; color: #888; margin-top: 5px; } | |
| .gifters { | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| padding: 20px; | |
| border-radius: 15px; | |
| border: 1px solid #333; | |
| } | |
| .pk-badge { | |
| background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); | |
| padding: 10px 20px; | |
| border-radius: 25px; | |
| display: inline-block; | |
| margin-top: 10px; | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>๐ก TikTok Radar</h1> | |
| <p style="opacity:0.8">v8.0 Premium Edition</p> | |
| </div> | |
| <div class="status"> | |
| ${isConnected ? '๐ข ู ุชุตู ุจุงูุจุซ ุงูู ุจุงุดุฑ' : '๐ด ูู ุงูุชุธุงุฑ ุงูุจุซ'} | |
| </div> | |
| <div style="text-align:center;padding:15px;background:#1a1a2e;border-radius:15px;margin-bottom:20px"> | |
| <div style="font-size:20px">๐ค @${CONFIG.TIKTOK_USERNAME}</div> | |
| <div style="color:#888;font-size:14px;margin-top:5px">โฐ ${new Date().toLocaleString('ar-IQ', {timeZone:'Asia/Baghdad'})}</div> | |
| </div> | |
| ${isConnected ? ` | |
| <div class="stats"> | |
| <div class="stat"> | |
| <div class="stat-value">๐ ${currentViewers}</div> | |
| <div class="stat-label">ุงูู ุดุงูุฏูู</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value">๐ ${maxViewers}</div> | |
| <div class="stat-label">ุงูุฃุนูู</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value">๐ ${totalDiamonds}</div> | |
| <div class="stat-label">ุงูู ุงุณุงุช</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value">๐ ${totalGifts}</div> | |
| <div class="stat-label">ุงููุฏุงูุง</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value">โค๏ธ ${totalLikes}</div> | |
| <div class="stat-label">ุงูุฅุนุฌุงุจุงุช</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value">๐ฌ ${totalComments}</div> | |
| <div class="stat-label">ุงูุชุนูููุงุช</div> | |
| </div> | |
| </div> | |
| <div class="gifters"> | |
| <h3 style="margin-bottom:15px;color:#667eea">๐ ุฃูุถู ุงูุฏุงุนู ูู</h3> | |
| ${topGiftersHtml} | |
| </div> | |
| ${pkActive ? '<div class="pk-badge">โ๏ธ ุฌููุฉ PK ูุดุทุฉ!</div>' : ''} | |
| ` : ''} | |
| </div> | |
| </body> | |
| </html> | |
| `); | |
| }); | |
| server.listen(PORT, '0.0.0.0', () => { | |
| console.log(''); | |
| console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'); | |
| console.log('โ ๐ฏ TikTok Radar Bot v8.0 Premium Edition ๐ฏ โ'); | |
| console.log('โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ'); | |
| console.log(`โ ๐ Server: http://localhost:${PORT} โ`); | |
| console.log(`โ ๐ค TikTok: @${CONFIG.TIKTOK_USERNAME.padEnd(40)}โ`); | |
| console.log(`โ ๐ฑ Telegram: ${CONFIG.TELEGRAM_TOKEN ? 'โ Connected' : 'โ Not Set'} โ`); | |
| console.log(`โ ๐ Session: ${CONFIG.SESSION_ID ? 'โ Authenticated' : 'โ ๏ธ Public Mode'} โ`); | |
| console.log(`โ ๐ Proxy: ${CONFIG.PROXY_URL ? 'โ Enabled' : 'โ Direct'} โ`); | |
| console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'); | |
| console.log(''); | |
| setTimeout(startBot, 2000); | |
| }); | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ฑ TELEGRAM API (Direct & Buttons) | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| async function sendTg(text, silent = false, buttons = null) { | |
| if (!CONFIG.TELEGRAM_TOKEN || !CONFIG.TELEGRAM_CHAT_ID) return false; | |
| const urls = []; | |
| if (CONFIG.PROXY_URL) urls.push(`${CONFIG.PROXY_URL}/bot${CONFIG.TELEGRAM_TOKEN}`); | |
| urls.push(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}`); | |
| for (const baseUrl of urls) { | |
| try { | |
| const payload = { | |
| chat_id: CONFIG.TELEGRAM_CHAT_ID, | |
| text, | |
| parse_mode: 'HTML', | |
| disable_notification: silent, | |
| disable_web_page_preview: true | |
| }; | |
| if (buttons) payload.reply_markup = { inline_keyboard: buttons }; | |
| const res = await axios.post(`${baseUrl}/sendMessage`, payload, { timeout: 15000 }); | |
| if (res.data?.ok) { | |
| console.log(`[Telegram] โ Message sent successfully`); | |
| return true; | |
| } | |
| } catch (e) { | |
| console.log(`[Telegram] โ ๏ธ Failed to send message`); | |
| } | |
| } | |
| return false; | |
| } | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ ๏ธ UTILITY FUNCTIONS | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| function esc(t) { | |
| return t ? String(t).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') : ''; | |
| } | |
| function formatK(n) { | |
| n = Number(n) || 0; | |
| if (n >= 1000000) return (n/1000000).toFixed(1) + 'M'; | |
| if (n >= 1000) return (n/1000).toFixed(1) + 'K'; | |
| return n.toString(); | |
| } | |
| function formatDuration(s) { | |
| if (!s) return '00:00:00'; | |
| const d = Math.floor((Date.now() - s.getTime()) / 1000); | |
| const h = Math.floor(d / 3600); | |
| const m = Math.floor((d % 3600) / 60); | |
| const sec = d % 60; | |
| return `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(sec).padStart(2,'0')}`; | |
| } | |
| function getTime() { | |
| return new Date().toLocaleString('ar-IQ', { | |
| timeZone: 'Asia/Baghdad', | |
| hour: '2-digit', | |
| minute: '2-digit', | |
| hour12: true | |
| }); | |
| } | |
| function getDate() { | |
| return new Date().toLocaleString('ar-IQ', { | |
| timeZone: 'Asia/Baghdad', | |
| year: 'numeric', | |
| month: '2-digit', | |
| day: '2-digit' | |
| }); | |
| } | |
| // ๐ Top Gifters Formatter | |
| function getTopGifters(limit = 5) { | |
| const gifters = Object.values(giftersMap) | |
| .sort((a, b) => b.coins - a.coins) | |
| .slice(0, limit); | |
| if (gifters.length === 0) return 'โข ูุง ููุฌุฏ ุฏุงุนู ูู ุจุนุฏ'; | |
| const medals = ['๐ฅ', '๐ฅ', '๐ฅ', '๐ ', '๐๏ธ', 'โญ', 'โจ', '๐ซ', '๐', 'โก']; | |
| return gifters.map((g, i) => { | |
| const medal = medals[i] || 'โข'; | |
| const name = esc(g.name); | |
| const username = g.username ? `\n โ <code>@${g.username}</code>` : ''; | |
| const coins = formatK(g.coins); | |
| return `${medal} <b>${name}</b>: ${coins} ๐${username}`; | |
| }).join('\n\n'); | |
| } | |
| // โ Top Followers Formatter | |
| function getTopFollowers(limit = 5) { | |
| const followers = Object.values(followersMap) | |
| .sort((a, b) => b.time - a.time) | |
| .slice(0, limit); | |
| if (followers.length === 0) return 'โข ูุง ููุฌุฏ ู ุชุงุจุนูู ุฌุฏุฏ'; | |
| return followers.map((f, i) => { | |
| const name = esc(f.name); | |
| const username = f.username ? `<code>@${f.username}</code>` : ''; | |
| return `${i + 1}. <b>${name}</b>\n โ ${username || 'ููุฒุฑ ุบูุฑ ู ุนุฑูู'}`; | |
| }).join('\n\n'); | |
| } | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ PERIODIC REPORTS | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| function startReports() { | |
| if (reportInterval) clearInterval(reportInterval); | |
| reportInterval = setInterval(() => { | |
| if (!isConnected) return; | |
| const liveLink = `https://www.tiktok.com/@${CONFIG.TIKTOK_USERNAME}/live`; | |
| const msg = | |
| `๐ <b>ุชูุฑูุฑ ุงูุจุซ ุงูู ุจุงุดุฑ</b>\n` + | |
| `โโโโโโโโโโโโโโโโโโโโโโ\n\n` + | |
| `๐ค <b>ุงูู ูุถูู:</b> ${CONFIG.TIKTOK_USERNAME}\n` + | |
| `๐ <code>@${CONFIG.TIKTOK_USERNAME}</code>\n\n` + | |
| `โฑ <b>ุงูู ุฏุฉ:</b> ${formatDuration(startTime)}\n` + | |
| `๐ <b>ุงูุชุงุฑูุฎ:</b> ${getDate()}\n\n` + | |
| `โโโโ ๐ ุงูุฅุญุตุงุฆูุงุช โโโโ\n\n` + | |
| `๐ ุงูู ุดุงูุฏูู ุงูุญุงูููู: <b>${formatK(currentViewers)}</b>\n` + | |
| `๐ ุฃุนูู ู ุดุงูุฏุฉ: <b>${formatK(maxViewers)}</b>\n` + | |
| `๐ ุฅุฌู ุงูู ุงูู ุงุณุงุช: <b>${formatK(totalDiamonds)}</b>\n` + | |
| `๐ ุนุฏุฏ ุงููุฏุงูุง: <b>${formatK(totalGifts)}</b>\n` + | |
| `โค๏ธ ุงูุฅุนุฌุงุจุงุช: <b>${formatK(totalLikes)}</b>\n` + | |
| `๐ฌ ุงูุชุนูููุงุช: <b>${formatK(totalComments)}</b>\n` + | |
| `โ ุงูู ุชุงุจุนูู ุงูุฌุฏุฏ: <b>${formatK(totalFollows)}</b>\n` + | |
| `โช๏ธ ุงูู ุดุงุฑูุงุช: <b>${formatK(totalShares)}</b>\n\n` + | |
| `โโโโ ๐ ุงูุฏุงุนู ูู โโโโ\n\n` + | |
| `${getTopGifters(5)}`; | |
| sendTg(msg, false, [ | |
| [{ text: '๐ด ุฏุฎูู ุงูุจุซ ุงูู ุจุงุดุฑ', url: liveLink }] | |
| ]); | |
| }, CONFIG.REPORT_INTERVAL * 60000); | |
| } | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ค MAIN BOT | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| async function startBot() { | |
| console.log(`\n[Bot] ๐ Searching for @${CONFIG.TIKTOK_USERNAME}...`); | |
| let TikTokLiveConnection, WebcastEvent, ControlEvent; | |
| try { | |
| const lib = require('tiktok-live-connector'); | |
| TikTokLiveConnection = lib.TikTokLiveConnection; | |
| WebcastEvent = lib.WebcastEvent; | |
| ControlEvent = lib.ControlEvent; | |
| console.log('[Bot] โ Library loaded successfully'); | |
| } catch (e) { | |
| console.error('[Bot] โ Library error:', e.message); | |
| setTimeout(startBot, 30000); | |
| return; | |
| } | |
| try { | |
| const options = { | |
| processInitialData: true, | |
| enableExtendedGiftInfo: true, | |
| fetchRoomInfoOnConnect: true, | |
| }; | |
| if (CONFIG.SESSION_ID && CONFIG.SESSION_ID.length > 10) { | |
| options.session = { | |
| cookie: { | |
| type: 'cookie', | |
| value: { | |
| sessionId: CONFIG.SESSION_ID, | |
| ttTargetIdc: CONFIG.TT_TARGET_IDC | |
| } | |
| } | |
| }; | |
| options.authenticateWs = true; | |
| console.log('[Bot] ๐ Using authenticated connection'); | |
| } else { | |
| console.log('[Bot] ๐ Using public connection'); | |
| } | |
| tiktokConnection = new TikTokLiveConnection(CONFIG.TIKTOK_USERNAME, options); | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ฎ CONTROL EVENTS | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // โ Connected | |
| tiktokConnection.on(ControlEvent.CONNECTED, (state) => { | |
| isConnected = true; | |
| startTime = new Date(); | |
| // Reset all stats | |
| totalGifts = 0; | |
| totalDiamonds = 0; | |
| totalLikes = 0; | |
| totalComments = 0; | |
| totalFollows = 0; | |
| totalShares = 0; | |
| maxViewers = 0; | |
| currentViewers = 0; | |
| giftersMap = {}; | |
| followersMap = {}; | |
| pkActive = false; | |
| console.log(`[Bot] โ Connected to room: ${state.roomId}`); | |
| const liveLink = `https://www.tiktok.com/@${CONFIG.TIKTOK_USERNAME}/live`; | |
| sendTg( | |
| `๐ก <b>ุงูุจุซ ุงูู ุจุงุดุฑ ุจุฏุฃ ุงูุขู!</b>\n` + | |
| `โโโโโโโโโโโโโโโโโโโโโโ\n\n` + | |
| `๐ฌ <b>ู ุนููู ุงุช ุงูุจุซ:</b>\n\n` + | |
| `๐ค <b>ุงูู ูุถูู:</b> ${CONFIG.TIKTOK_USERNAME}\n` + | |
| `๐ <b>ุงูููุฒุฑ:</b> <code>@${CONFIG.TIKTOK_USERNAME}</code>\n` + | |
| `โฐ <b>ููุช ุงูุจุฏุก:</b> ${getTime()}\n` + | |
| `๐ <b>ุงูุชุงุฑูุฎ:</b> ${getDate()}\n\n` + | |
| `โโโโโโโโโโโโโโโโโโโโโโ\n` + | |
| `๐ <b>ุงูุจุซ ุจุฏุฃ! ุงูุถู ุงูุขู ูุงุฏุนู !</b>`, | |
| false, | |
| [ | |
| [{ text: '๐ด ุฏุฎูู ุงูุจุซ ุงูู ุจุงุดุฑ', url: liveLink }], | |
| [{ text: '๐ ุงูุฅุญุตุงุฆูุงุช', url: `https://www.tiktok.com/@${CONFIG.TIKTOK_USERNAME}` }] | |
| ] | |
| ); | |
| startReports(); | |
| }); | |
| // ๐ด Disconnected | |
| tiktokConnection.on(ControlEvent.DISCONNECTED, ({ code, reason }) => { | |
| isConnected = false; | |
| console.log(`[Bot] ๐ด Disconnected (code: ${code}, reason: ${reason || 'unknown'})`); | |
| if (reportInterval) clearInterval(reportInterval); | |
| scheduleReconnect(30000); | |
| }); | |
| // โ ๏ธ Error | |
| tiktokConnection.on(ControlEvent.ERROR, (err) => { | |
| console.error('[Bot] โ ๏ธ Error:', err?.info || err?.message || err); | |
| }); | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐บ WEBCAST EVENTS | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ด Stream End | |
| tiktokConnection.on(WebcastEvent.STREAM_END, ({ action }) => { | |
| isConnected = false; | |
| console.log(`[Bot] ๐ด Stream ended (action: ${action})`); | |
| if (reportInterval) clearInterval(reportInterval); | |
| sendTg( | |
| `๐ด <b>ุงูุชูู ุงูุจุซ ุงูู ุจุงุดุฑ</b>\n` + | |
| `โโโโโโโโโโโโโโโโโโโโโโ\n\n` + | |
| `๐ค <b>ุงูู ูุถูู:</b> ${CONFIG.TIKTOK_USERNAME}\n` + | |
| `๐ <code>@${CONFIG.TIKTOK_USERNAME}</code>\n\n` + | |
| `โโโโ ๐ ู ูุฎุต ุงูุจุซ โโโโ\n\n` + | |
| `โฑ <b>ู ุฏุฉ ุงูุจุซ:</b> ${formatDuration(startTime)}\n` + | |
| `๐ <b>ุฃุนูู ู ุดุงูุฏุฉ:</b> ${formatK(maxViewers)}\n` + | |
| `๐ <b>ุฅุฌู ุงูู ุงูู ุงุณุงุช:</b> ${formatK(totalDiamonds)}\n` + | |
| `๐ <b>ุนุฏุฏ ุงููุฏุงูุง:</b> ${formatK(totalGifts)}\n` + | |
| `โค๏ธ <b>ุงูุฅุนุฌุงุจุงุช:</b> ${formatK(totalLikes)}\n` + | |
| `๐ฌ <b>ุงูุชุนูููุงุช:</b> ${formatK(totalComments)}\n` + | |
| `โ <b>ุงูู ุชุงุจุนูู ุงูุฌุฏุฏ:</b> ${formatK(totalFollows)}\n\n` + | |
| `โโโโ ๐ ุฃูุถู ุงูุฏุงุนู ูู โโโโ\n\n` + | |
| `${getTopGifters(5)}\n\n` + | |
| `โโโโโโโโโโโโโโโโโโโโโโ\n` + | |
| `๐ <b>ุดูุฑุงู ููู ู ู ุญุถุฑ ูุฏุนู !</b>` | |
| ); | |
| scheduleReconnect(60000); | |
| }); | |
| // ๐ฌ Chat | |
| tiktokConnection.on(WebcastEvent.CHAT, (data) => { | |
| totalComments++; | |
| const nickname = data.user?.nickname || data.user?.uniqueId || '?'; | |
| const comment = data.comment || ''; | |
| console.log(`[Chat] ๐ฌ ${nickname}: ${comment}`); | |
| }); | |
| // ๐ Gift - FIXED! | |
| tiktokConnection.on(WebcastEvent.GIFT, (data) => { | |
| // User info | |
| const uniqueId = data.user?.uniqueId || data.uniqueId || ''; | |
| const oderId = data.user?.userId || data.userId || uniqueId || 'unknown'; | |
| const nickname = data.user?.nickname || data.nickname || uniqueId || '?'; | |
| // Gift info - check ALL possible sources | |
| const giftId = data.giftId || data.gift?.gift_id || 0; | |
| const giftName = data.giftName | |
| || data.extendedGiftInfo?.name | |
| || data.gift?.name | |
| || data.describe?.replace('Sent ', '') | |
| || `Gift#${giftId}`; | |
| // Gift type | |
| const giftType = data.giftType ?? data.gift?.gift_type ?? 0; | |
| const repeatCount = data.repeatCount ?? data.gift?.repeat_count ?? 1; | |
| const repeatEnd = data.repeatEnd ?? data.gift?.repeat_end ?? true; | |
| // ๐ Diamond count - FIXED: Check all sources correctly | |
| let diamondCount = 0; | |
| // Priority order for finding diamond count | |
| if (data.diamondCount && data.diamondCount > 0) { | |
| diamondCount = data.diamondCount; | |
| } else if (data.extendedGiftInfo?.diamondCount && data.extendedGiftInfo.diamondCount > 0) { | |
| diamondCount = data.extendedGiftInfo.diamondCount; | |
| } else if (data.extendedGiftInfo?.diamond_count && data.extendedGiftInfo.diamond_count > 0) { | |
| diamondCount = data.extendedGiftInfo.diamond_count; | |
| } else if (data.gift?.diamond_count && data.gift.diamond_count > 0) { | |
| diamondCount = data.gift.diamond_count; | |
| } else if (data.giftDetails?.diamondCount && data.giftDetails.diamondCount > 0) { | |
| diamondCount = data.giftDetails.diamondCount; | |
| } | |
| // Log for debugging | |
| console.log(`[Gift] ๐ ${nickname} -> ${giftName}`); | |
| console.log(`[Gift] ๐ Diamonds: ${diamondCount} x ${repeatCount} = ${diamondCount * repeatCount}`); | |
| console.log(`[Gift] Type: ${giftType}, RepeatEnd: ${repeatEnd}`); | |
| // Skip streak gifts until they end | |
| if (giftType === 1 && repeatEnd === false) { | |
| console.log(`[Gift] โณ Streak in progress...`); | |
| return; | |
| } | |
| // Calculate total | |
| const totalCost = diamondCount * repeatCount; | |
| // Update totals | |
| totalGifts++; | |
| totalDiamonds += totalCost; | |
| // Track gifter | |
| if (!giftersMap[oderId]) { | |
| giftersMap[oderId] = { | |
| name: nickname, | |
| username: uniqueId, | |
| coins: 0, | |
| count: 0 | |
| }; | |
| } | |
| giftersMap[oderId].coins += totalCost; | |
| giftersMap[oderId].count++; | |
| // Track PK gifts | |
| if (pkActive) { | |
| if (!pkInfo.pkGifts[oderId]) { | |
| pkInfo.pkGifts[oderId] = { name: nickname, username: uniqueId, coins: 0 }; | |
| } | |
| pkInfo.pkGifts[oderId].coins += totalCost; | |
| } | |
| console.log(`[Gift] โ Recorded: ${nickname} = ${totalCost}๐ (Total in map: ${giftersMap[oderId].coins}๐)`); | |
| // Send notification | |
| let emoji = '๐'; | |
| if (totalCost >= 10000) emoji = '๐๐ฅ'; | |
| else if (totalCost >= 5000) emoji = '๐โจ'; | |
| else if (totalCost >= 1000) emoji = '๐'; | |
| else if (totalCost >= 100) emoji = '๐โจ'; | |
| const userLink = uniqueId ? `\n๐ <code>@${uniqueId}</code>` : ''; | |
| sendTg( | |
| `${emoji} <b>ูุฏูุฉ ุฌุฏูุฏุฉ!</b>\n` + | |
| `โโโโโโโโโโโโโโโ\n\n` + | |
| `๐ค <b>${esc(nickname)}</b>${userLink}\n\n` + | |
| `๐ ุฃุฑุณู: <b>${esc(giftName)}</b>\n` + | |
| `๐ ุงูููู ุฉ: <b>${formatK(totalCost)}</b> ู ุงุณุฉ` + | |
| (repeatCount > 1 ? ` (x${repeatCount})` : ''), | |
| totalCost < 50 | |
| ); | |
| }); | |
| // โค๏ธ Like | |
| tiktokConnection.on(WebcastEvent.LIKE, (data) => { | |
| const likes = data.likeCount || data.totalLikeCount || 1; | |
| totalLikes += likes; | |
| }); | |
| // โ Follow - Enhanced | |
| tiktokConnection.on(WebcastEvent.FOLLOW, (data) => { | |
| totalFollows++; | |
| const uniqueId = data.user?.uniqueId || ''; | |
| const nickname = data.user?.nickname || uniqueId || '?'; | |
| const oderId = data.user?.userId || uniqueId || Date.now().toString(); | |
| // Track follower | |
| followersMap[oderId] = { | |
| name: nickname, | |
| username: uniqueId, | |
| time: Date.now() | |
| }; | |
| console.log(`[Follow] โ ${nickname} (@${uniqueId})`); | |
| const userLink = uniqueId ? `\n๐ <code>@${uniqueId}</code>` : ''; | |
| sendTg( | |
| `โ <b>ู ุชุงุจุน ุฌุฏูุฏ!</b>\n` + | |
| `โโโโโโโโโโโโโโโ\n\n` + | |
| `๐ค <b>${esc(nickname)}</b>${userLink}\n\n` + | |
| `๐ ุดูุฑุงู ุนูู ุงูู ุชุงุจุนุฉ!`, | |
| true | |
| ); | |
| }); | |
| // โช๏ธ Share | |
| tiktokConnection.on(WebcastEvent.SHARE, (data) => { | |
| totalShares++; | |
| const nickname = data.user?.nickname || data.user?.uniqueId || '?'; | |
| console.log(`[Share] โช๏ธ ${nickname} shared the stream`); | |
| }); | |
| // ๐ Viewer Count | |
| tiktokConnection.on(WebcastEvent.ROOM_USER, (data) => { | |
| currentViewers = data.viewerCount || 0; | |
| if (currentViewers > maxViewers) maxViewers = currentViewers; | |
| }); | |
| // ๐ค Member Join | |
| tiktokConnection.on(WebcastEvent.MEMBER, (data) => { | |
| const nickname = data.user?.nickname || data.user?.uniqueId || '?'; | |
| console.log(`[Member] ๐ค ${nickname} joined`); | |
| }); | |
| // ๐ฆ Envelope | |
| tiktokConnection.on(WebcastEvent.ENVELOPE, (data) => { | |
| if (data.envelopeInfo) { | |
| const sender = data.envelopeInfo.sendUserName || '?'; | |
| const diamonds = data.envelopeInfo.diamondCount || 0; | |
| console.log(`[Envelope] ๐ฆ ${sender} sent treasure box (${diamonds}๐)`); | |
| sendTg( | |
| `๐ฆ <b>ุตูุฏูู ููุฒ!</b>\n` + | |
| `โโโโโโโโโโโโโโโ\n\n` + | |
| `๐ค <b>${esc(sender)}</b>\n` + | |
| `๐ ุงูููู ุฉ: <b>${formatK(diamonds)}</b> ู ุงุณุฉ` | |
| ); | |
| } | |
| }); | |
| // โ๏ธ PK Battle Start - Enhanced | |
| tiktokConnection.on(WebcastEvent.LINK_MIC_BATTLE, (data) => { | |
| pkActive = true; | |
| pkInfo = { | |
| battleId: data.battleId || '', | |
| participants: [], | |
| participantDetails: [], | |
| ourScore: 0, | |
| theirScore: 0, | |
| startTime: new Date(), | |
| pkGifts: {}, | |
| }; | |
| console.log(`[PK] ๐ฆ Raw data:`, JSON.stringify(data.anchorInfo || {}).substring(0, 500)); | |
| // Extract participants | |
| const participantDetails = []; | |
| const anchorInfo = data.anchorInfo || {}; | |
| for (const [key, info] of Object.entries(anchorInfo)) { | |
| const user = info.user || info || {}; | |
| const displayId = user.displayId || user.display_id || user.uniqueId || user.unique_id || ''; | |
| const nickName = user.nickName || user.nickname || user.nick_name || displayId || 'ู ุฌููู'; | |
| const oderId = user.userId || user.user_id || user.id || key || ''; | |
| if (displayId || nickName !== 'ู ุฌููู') { | |
| participantDetails.push({ | |
| name: nickName, | |
| username: displayId, | |
| oderId: oderId, | |
| }); | |
| } | |
| } | |
| pkInfo.participantDetails = participantDetails; | |
| pkInfo.participants = participantDetails.map(p => p.name); | |
| console.log(`[PK] โ๏ธ Battle started: ${data.battleId}`); | |
| console.log(`[PK] ๐ฅ Participants:`, participantDetails); | |
| // Find opponent | |
| const host = participantDetails.find(p => | |
| p.username === CONFIG.TIKTOK_USERNAME || p.name === CONFIG.TIKTOK_USERNAME | |
| ) || participantDetails[0] || null; | |
| const opponent = participantDetails.find(p => | |
| p.username !== CONFIG.TIKTOK_USERNAME && p.name !== CONFIG.TIKTOK_USERNAME | |
| ) || participantDetails[1] || null; | |
| const liveLink = `https://www.tiktok.com/@${CONFIG.TIKTOK_USERNAME}/live`; | |
| let pkMsg = | |
| `โ๏ธ๐ฅ <b>ุจุฏุฃุช ุฌููุฉ PK ุฌุฏูุฏุฉ!</b>\n` + | |
| `โโโโโโโโโโโโโโโโโโโโโโ\n\n`; | |
| // Host info | |
| pkMsg += `๐ <b>ุตุงุญุจ ุงูุจุซ:</b>\n` + | |
| ` ๐ค <b>${esc(CONFIG.TIKTOK_USERNAME)}</b>\n` + | |
| ` ๐ <code>@${CONFIG.TIKTOK_USERNAME}</code>\n\n`; | |
| pkMsg += ` ๐\n\n`; | |
| // Opponent info | |
| if (opponent) { | |
| pkMsg += `๐ฅ <b>ุงูู ูุงูุณ:</b>\n` + | |
| ` ๐ค <b>${esc(opponent.name)}</b>\n` + | |
| ` ๐ <code>@${opponent.username || 'ุบูุฑ ู ุนุฑูู'}</code>\n\n`; | |
| } else { | |
| pkMsg += `๐ฅ <b>ุงูู ูุงูุณ:</b>\n` + | |
| ` โณ ุฌุงุฑู ุชุญู ูู ุงูุจูุงูุงุช...\n\n`; | |
| } | |
| pkMsg += `โโโโโโโโโโโโโโโโโโโโโโ\n` + | |
| `๐ <b>ุงุฏุนู ูุง ุงูุจุซ ูุณุงูู ูุง ุจุงูููุฒ!</b>\n` + | |
| `๐ <b>ูู ูุฏูุฉ ุชุญุณุจ ูู ุงููุชูุฌุฉ!</b>`; | |
| sendTg(pkMsg, false, [ | |
| [{ text: '๐ด ุงุฏุฎู ุงูุจุซ ูุงุฏุนู ุงูุขู!', url: liveLink }] | |
| ]); | |
| }); | |
| // ๐ PK Update | |
| tiktokConnection.on(WebcastEvent.LINK_MIC_ARMIES, (data) => { | |
| if (!pkActive) return; | |
| if (data.totalDiamondCount) { | |
| pkInfo.ourScore = data.totalDiamondCount; | |
| console.log(`[PK] ๐ Score update: ${data.totalDiamondCount}๐`); | |
| } | |
| }); | |
| // ๐ฌ Live Intro | |
| tiktokConnection.on(WebcastEvent.LIVE_INTRO, (data) => { | |
| const host = data.host?.nickname || data.host?.uniqueId || ''; | |
| const desc = data.description || ''; | |
| if (host || desc) { | |
| console.log(`[Intro] ๐ฌ Host: ${host}, Description: ${desc}`); | |
| } | |
| }); | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ CONNECT | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| console.log('[Bot] ๐ Connecting to TikTok...'); | |
| await tiktokConnection.connect(); | |
| } catch (err) { | |
| const errMsg = err.message || String(err); | |
| console.error('[Bot] โ Connection failed:', errMsg); | |
| isConnected = false; | |
| if (errMsg.includes('offline') || errMsg.includes('not online')) { | |
| console.log('[Bot] ๐ด User is not live, will retry...'); | |
| } | |
| scheduleReconnect(60000); | |
| } | |
| } | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ RECONNECTION | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| function scheduleReconnect(delay) { | |
| if (reconnectTimer) clearTimeout(reconnectTimer); | |
| console.log(`[Bot] ๐ Reconnecting in ${delay/1000} seconds...`); | |
| reconnectTimer = setTimeout(() => { | |
| reconnectTimer = null; | |
| if (!isConnected) startBot(); | |
| }, delay); | |
| } | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| // ๐ก๏ธ ERROR HANDLING & KEEP ALIVE | |
| // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| process.on('uncaughtException', (e) => { | |
| console.error('[FATAL] Uncaught Exception:', e.message); | |
| }); | |
| process.on('unhandledRejection', (r) => { | |
| console.error('[FATAL] Unhandled Rejection:', r); | |
| }); | |
| // Keep alive ping | |
| setInterval(() => { | |
| http.get(`http://localhost:${PORT}`, r => r.resume()).on('error', () => {}); | |
| }, 60000); | |
| // Graceful shutdown | |
| process.on('SIGINT', async () => { | |
| console.log('\n[Bot] ๐ Shutting down gracefully...'); | |
| if (tiktokConnection) { | |
| try { await tiktokConnection.disconnect(); } catch(e) {} | |
| } | |
| await sendTg( | |
| `๐ค <b>ุงูุจูุช ุชููู ู ุคูุชุงู</b>\n` + | |
| `โโโโโโโโโโโโโโโ\n` + | |
| `โฐ ${getTime()}\n` + | |
| `๐ ${getDate()}` | |
| ); | |
| process.exit(0); | |
| }); | |
| console.log('[Bot] ๐ TikTok Radar v8.0 Premium initialized!'); |