Update bot.js
Browse files
bot.js
CHANGED
|
@@ -1,185 +1,111 @@
|
|
| 1 |
/**
|
| 2 |
-
*
|
| 3 |
-
*
|
| 4 |
-
* ║ Based on tiktok-live-connector v2.1+ API ║
|
| 5 |
-
* ╚══════════════════════════════════════════════════════════════════════╝
|
| 6 |
*/
|
| 7 |
|
| 8 |
const { TikTokLiveConnection, WebcastEvent, ControlEvent } = require('tiktok-live-connector');
|
| 9 |
const axios = require('axios');
|
| 10 |
const http = require('http');
|
| 11 |
|
| 12 |
-
|
| 13 |
-
function cleanEnv(val, fallback) {
|
| 14 |
-
if (!val) return fallback;
|
| 15 |
-
return val.toString().trim().split('\n')[0].trim();
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
const CONFIG = {
|
| 19 |
-
TIKTOK_USERNAME: cleanEnv(process.env.TIKTOK_USERNAME, 'a200_89'),
|
| 20 |
-
SESSION_ID: cleanEnv(process.env.SESSION_ID, ''),
|
| 21 |
-
TT_TARGET_IDC: cleanEnv(process.env.TT_TARGET_IDC, 'alisg'),
|
| 22 |
-
TELEGRAM_TOKEN: cleanEnv(process.env.TELEGRAM_TOKEN, ''),
|
| 23 |
-
TELEGRAM_CHAT_ID: cleanEnv(process.env.TELEGRAM_CHAT_ID, ''),
|
| 24 |
-
PROXY_URL: cleanEnv(process.env.PROXY_URL, '').replace(/\/$/, ''),
|
| 25 |
-
REPORT_INTERVAL_MINUTES: parseInt(cleanEnv(process.env.REPORT_INTERVAL, '10')) || 10,
|
| 26 |
-
CHAT_COOLDOWN_MS: 4000,
|
| 27 |
-
GIFT_COOLDOWN_MS: 3000,
|
| 28 |
-
LIKE_BATCH_THRESHOLD: 50,
|
| 29 |
-
TOP_CHAT_LIMIT: 10,
|
| 30 |
-
SPAM_KEYWORDS: ['spam', 'scam', 'fake', 'click here', 'free money', 'earn now', 'www.', '.com'],
|
| 31 |
-
};
|
| 32 |
-
|
| 33 |
-
// متغيرات الحالة
|
| 34 |
-
let isConnected = false;
|
| 35 |
-
let isLive = false;
|
| 36 |
-
let maxViewers = 0;
|
| 37 |
-
let totalLikes = 0;
|
| 38 |
-
let totalShares = 0;
|
| 39 |
-
let totalGifts = 0;
|
| 40 |
-
let totalFollows = 0;
|
| 41 |
-
let totalComments = 0;
|
| 42 |
-
let totalEnvelopes = 0;
|
| 43 |
-
let totalCoinsGiven = 0;
|
| 44 |
-
let giftersMap = {};
|
| 45 |
-
let likersMap = {};
|
| 46 |
-
let sharersMap = {};
|
| 47 |
-
let followersMap = {};
|
| 48 |
-
let chattersMap = {};
|
| 49 |
-
let moderatorsMap = {};
|
| 50 |
-
let envelopeWinnersMap = {};
|
| 51 |
-
let coinPurseWinnersMap = {};
|
| 52 |
-
let topChatMessages = [];
|
| 53 |
-
let startTime = null;
|
| 54 |
-
let lastReportTime = null;
|
| 55 |
-
let tiktokConnection = null;
|
| 56 |
-
let reconnectTimer = null;
|
| 57 |
-
let reportInterval = null;
|
| 58 |
-
let lastMessageId = null;
|
| 59 |
-
let reconnectAttempt = 0;
|
| 60 |
-
let lastReconnectNotify = 0;
|
| 61 |
-
let lastActivity = Date.now();
|
| 62 |
-
|
| 63 |
-
const cooldowns = {
|
| 64 |
-
chat: new Map(), gift: new Map(), like: new Map(), follow: new Map(),
|
| 65 |
-
share: new Map(), envelope: new Map(), coinPurse: new Map(), moderator: new Map(),
|
| 66 |
-
};
|
| 67 |
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
|
| 76 |
-
if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
|
| 77 |
-
return num.toString();
|
| 78 |
-
}
|
| 79 |
-
function getBaghdadTime() {
|
| 80 |
-
return new Intl.DateTimeFormat('ar-IQ', { timeZone: 'Asia/Baghdad', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true }).format(new Date());
|
| 81 |
-
}
|
| 82 |
-
function escapeHtml(text) {
|
| 83 |
-
if (!text) return '';
|
| 84 |
-
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
| 85 |
-
}
|
| 86 |
|
| 87 |
-
//
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
}
|
| 95 |
|
| 96 |
-
// إرسال لتيليجرام
|
| 97 |
-
async function
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
return response.data;
|
| 109 |
-
} catch (e) { console.error(`[Telegram] Error:`, e.message); return null; }
|
| 110 |
}
|
| 111 |
|
| 112 |
-
// إ
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
processInitialData: true,
|
| 116 |
-
enableExtendedGiftInfo: true,
|
| 117 |
-
webClientParams: { app_language: 'ar-IQ', device_platform: 'web' },
|
| 118 |
-
};
|
| 119 |
-
if (CONFIG.SESSION_ID) {
|
| 120 |
-
options.sessionId = CONFIG.SESSION_ID;
|
| 121 |
-
options.ttTargetIdc = CONFIG.TT_TARGET_IDC || 'alisg';
|
| 122 |
-
options.authenticateWs = true;
|
| 123 |
-
}
|
| 124 |
-
return new TikTokLiveConnection(CONFIG.TIKTOK_USERNAME, options);
|
| 125 |
-
}
|
| 126 |
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
}
|
| 141 |
-
});
|
| 142 |
-
|
| 143 |
-
conn.on(WebcastEvent.GIFT, (data) => {
|
| 144 |
-
updateActivity();
|
| 145 |
-
if (data.giftType === 1 && !data.repeatEnd) return; // تخطي الهدايا المتتالية حتى تنتهي
|
| 146 |
-
const totalCost = data.diamondCount * data.repeatCount;
|
| 147 |
-
totalGifts++;
|
| 148 |
-
const nickname = data.user?.nickname || data.user?.uniqueId || 'مجهول';
|
| 149 |
-
sendTelegram(`🎁 ${nickname} أرسل ${data.giftName} (x${data.repeatCount}) \n💎 ${totalCost} ماسة`, null, null, 'HTML', null, totalCost < 100);
|
| 150 |
-
});
|
| 151 |
-
|
| 152 |
-
conn.on(WebcastEvent.LIKE, (data) => {
|
| 153 |
-
totalLikes += data.likeCount;
|
| 154 |
-
if (data.likeCount > 50) {
|
| 155 |
-
const nickname = data.user?.nickname || 'مجهول';
|
| 156 |
-
sendTelegram(`❤️ ${nickname} أرسل ${data.likeCount} إعجاب!`, null, null, 'HTML', null, true);
|
| 157 |
-
}
|
| 158 |
-
});
|
| 159 |
-
|
| 160 |
-
conn.on(WebcastEvent.STREAM_END, () => {
|
| 161 |
-
isConnected = false; isLive = false;
|
| 162 |
-
sendTelegram(`🔴 انتهى البث المباشر.`);
|
| 163 |
-
});
|
| 164 |
-
|
| 165 |
-
conn.on(ControlEvent.ERROR, (err) => console.error('[TikTok Error]', err));
|
| 166 |
}
|
| 167 |
|
| 168 |
-
|
| 169 |
-
try {
|
| 170 |
-
tiktokConnection = createConnection();
|
| 171 |
-
setupEvents(tiktokConnection);
|
| 172 |
-
await tiktokConnection.connect();
|
| 173 |
-
} catch (err) {
|
| 174 |
-
console.error('[Radar] Failed:', err.message);
|
| 175 |
-
setTimeout(startRadar, 30000);
|
| 176 |
-
}
|
| 177 |
-
}
|
| 178 |
-
|
| 179 |
-
// سيرفر بسيط للبقاء حياً
|
| 180 |
-
http.createServer((req, res) => {
|
| 181 |
-
res.writeHead(200);
|
| 182 |
-
res.end(`TikTok Bot Active | @${CONFIG.TIKTOK_USERNAME}`);
|
| 183 |
-
}).listen(process.env.PORT || 7860);
|
| 184 |
-
|
| 185 |
-
startRadar();
|
|
|
|
| 1 |
/**
|
| 2 |
+
* ⚡ TikTok Radar Pro v6.5 - High Performance Edition
|
| 3 |
+
* تم الإصلاح للعمل على Hugging Face Spaces 2026
|
|
|
|
|
|
|
| 4 |
*/
|
| 5 |
|
| 6 |
const { TikTokLiveConnection, WebcastEvent, ControlEvent } = require('tiktok-live-connector');
|
| 7 |
const axios = require('axios');
|
| 8 |
const http = require('http');
|
| 9 |
|
| 10 |
+
console.log('🚀 بدء تشغيل البوت...');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
+
// 1. تشغيل السيرفر فوراً لإرضاء Hugging Face ومنع تعليق البناء
|
| 13 |
+
const PORT = process.env.PORT || 7860;
|
| 14 |
+
const server = http.createServer((req, res) => {
|
| 15 |
+
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
|
| 16 |
+
res.end(`TikTok Bot Active | @${process.env.TIKTOK_USERNAME || 'a200_89'}`);
|
| 17 |
+
});
|
| 18 |
|
| 19 |
+
server.listen(PORT, '0.0.0.0', () => {
|
| 20 |
+
console.log(`✅ السيرفر يعمل على المنفذ ${PORT}`);
|
| 21 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
// 2. الإعدادات من المتغيرات البيئية
|
| 24 |
+
const CONFIG = {
|
| 25 |
+
TIKTOK_USERNAME: (process.env.TIKTOK_USERNAME || 'a200_89').trim(),
|
| 26 |
+
SESSION_ID: (process.env.SESSION_ID || '').trim(),
|
| 27 |
+
TT_TARGET_IDC: (process.env.TT_TARGET_IDC || 'alisg').trim(),
|
| 28 |
+
TELEGRAM_TOKEN: (process.env.TELEGRAM_TOKEN || '').trim(),
|
| 29 |
+
TELEGRAM_CHAT_ID: (process.env.TELEGRAM_CHAT_ID || '').trim(),
|
| 30 |
+
};
|
| 31 |
|
| 32 |
+
// 3. دالة إرسال التنبيهات لتيليجرام
|
| 33 |
+
async function sendTg(text) {
|
| 34 |
+
if (!CONFIG.TELEGRAM_TOKEN) return;
|
| 35 |
+
try {
|
| 36 |
+
await axios.post(`https://api.telegram.org/bot${CONFIG.TELEGRAM_TOKEN}/sendMessage`, {
|
| 37 |
+
chat_id: CONFIG.TELEGRAM_CHAT_ID,
|
| 38 |
+
text: text,
|
| 39 |
+
parse_mode: 'HTML'
|
| 40 |
+
});
|
| 41 |
+
} catch (e) {
|
| 42 |
+
console.error('❌ خطأ في تيليجرام:', e.message);
|
| 43 |
+
}
|
|
|
|
|
|
|
| 44 |
}
|
| 45 |
|
| 46 |
+
// 4. إدارة الاتصال بتيك توك
|
| 47 |
+
let tiktokConnection = null;
|
| 48 |
+
let isConnected = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
+
async function connectToTikTok() {
|
| 51 |
+
console.log(`🔎 محاولة الاتصال بحساب: @${CONFIG.TIKTOK_USERNAME}`);
|
| 52 |
+
|
| 53 |
+
try {
|
| 54 |
+
const options = {
|
| 55 |
+
processInitialData: true,
|
| 56 |
+
enableExtendedGiftInfo: true,
|
| 57 |
+
webClientParams: { app_language: 'ar-IQ', device_platform: 'web' },
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
if (CONFIG.SESSION_ID) {
|
| 61 |
+
options.sessionId = CONFIG.SESSION_ID;
|
| 62 |
+
options.ttTargetIdc = CONFIG.TT_TARGET_IDC;
|
| 63 |
+
options.authenticateWs = true;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
tiktokConnection = new TikTokLiveConnection(CONFIG.TIKTOK_USERNAME, options);
|
| 67 |
+
|
| 68 |
+
tiktokConnection.on(ControlEvent.CONNECTED, (state) => {
|
| 69 |
+
isConnected = true;
|
| 70 |
+
console.log(`✅ متصل بنجاح! ID الغرفة: ${state.roomId}`);
|
| 71 |
+
sendTg(`📡 <b>تم الاتصال بالبث المباشر!</b>\n👤 المُضيف: @${CONFIG.TIKTOK_USERNAME}`);
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
tiktokConnection.on(WebcastEvent.CHAT, (data) => {
|
| 75 |
+
console.log(`💬 ${data.user.nickname}: ${data.comment}`);
|
| 76 |
+
});
|
| 77 |
+
|
| 78 |
+
tiktokConnection.on(WebcastEvent.GIFT, (data) => {
|
| 79 |
+
if (data.giftType === 1 && !data.repeatEnd) return;
|
| 80 |
+
const coins = data.diamondCount * data.repeatCount;
|
| 81 |
+
if (coins >= 1) { // يمكنك تغيير هذا الرقم لتنبيهك بالهدايا الكبيرة فقط
|
| 82 |
+
sendTg(`🎁 <b>${data.user.nickname}</b> أرسل <b>${data.giftName}</b> (x${data.repeatCount})\n💎 القيمة: ${coins} ماسة`);
|
| 83 |
+
}
|
| 84 |
+
});
|
| 85 |
+
|
| 86 |
+
tiktokConnection.on(WebcastEvent.STREAM_END, () => {
|
| 87 |
+
isConnected = false;
|
| 88 |
+
console.log('🔴 انتهى البث.');
|
| 89 |
+
sendTg(`🔴 <b>انتهى البث المباشر لـ @${CONFIG.TIKTOK_USERNAME}</b>`);
|
| 90 |
+
setTimeout(connectToTikTok, 60000);
|
| 91 |
+
});
|
| 92 |
+
|
| 93 |
+
tiktokConnection.on(ControlEvent.DISCONNECTED, () => {
|
| 94 |
+
isConnected = false;
|
| 95 |
+
console.log('📴 انقطع الاتصال، جاري المحاولة مرة أخرى...');
|
| 96 |
+
setTimeout(connectToTikTok, 30000);
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
+
tiktokConnection.on(ControlEvent.ERROR, (err) => {
|
| 100 |
+
console.error('⚠️ خطأ:', err.info || err);
|
| 101 |
+
});
|
| 102 |
+
|
| 103 |
+
await tiktokConnection.connect();
|
| 104 |
+
|
| 105 |
+
} catch (err) {
|
| 106 |
+
console.error('❌ فشل الاتصال:', err.message);
|
| 107 |
+
setTimeout(connectToTikTok, 30000);
|
| 108 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
}
|
| 110 |
|
| 111 |
+
connectToTikTok();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|