Radar / bot.js
Reooiq's picture
chore: remove proxy/tunnel configurations and switch to direct API
38ef38d
Raw History Blame Contribute Delete
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,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') : '';
}
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!');