Spaces:
Running
Running
| <html lang="fa" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' https://eitaayar.ir; connect-src https://eitaayar.ir;"> | |
| <title>🤖 ربات هوشمند ایتا - نسخه 2.0</title> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, sans-serif; | |
| background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%); | |
| min-height: 100vh; padding: 20px; color: #fff; | |
| } | |
| .container { | |
| max-width: 1200px; margin: 0 auto; | |
| display: grid; grid-template-columns: 350px 1fr; gap: 20px; | |
| } | |
| @media (max-width: 968px) { .container { grid-template-columns: 1fr; } } | |
| .panel { | |
| background: rgba(255,255,255,0.05); backdrop-filter: blur(20px); | |
| border: 1px solid rgba(255,255,255,0.1); border-radius: 20px; | |
| padding: 25px; box-shadow: 0 20px 40px rgba(0,0,0,0.3); | |
| } | |
| .panel h2 { | |
| font-size: 18px; margin-bottom: 20px; display: flex; | |
| align-items: center; gap: 10px; color: #00d2ff; | |
| } | |
| .panel h2 .icon { | |
| width: 40px; height: 40px; border-radius: 12px; | |
| background: linear-gradient(135deg, #00d2ff, #3a7bd5); | |
| display: flex; align-items: center; justify-content: center; font-size: 20px; | |
| } | |
| .form-group { margin-bottom: 18px; } | |
| .form-group label { | |
| display: block; font-size: 13px; font-weight: 600; | |
| margin-bottom: 8px; color: rgba(255,255,255,0.8); | |
| } | |
| .form-group input, .form-group textarea, .form-group select { | |
| width: 100%; padding: 12px 15px; | |
| background: rgba(255,255,255,0.07); border: 2px solid rgba(255,255,255,0.1); | |
| border-radius: 10px; color: #fff; font-size: 14px; | |
| font-family: inherit; outline: none; transition: all 0.3s; | |
| } | |
| .form-group input:focus, .form-group textarea:focus { | |
| border-color: #00d2ff; background: rgba(255,255,255,0.1); | |
| } | |
| .input-with-toggle { position: relative; } | |
| .input-with-toggle input { padding-left: 45px; } | |
| .toggle-vis { | |
| position: absolute; left: 10px; top: 50%; transform: translateY(-50%); | |
| background: none; border: none; color: rgba(255,255,255,0.5); | |
| cursor: pointer; font-size: 16px; | |
| } | |
| .btn { | |
| width: 100%; padding: 14px; border: none; border-radius: 10px; | |
| font-size: 15px; font-weight: 700; font-family: inherit; | |
| cursor: pointer; transition: all 0.3s; display: flex; | |
| align-items: center; justify-content: center; gap: 8px; | |
| } | |
| .btn-primary { background: linear-gradient(135deg, #00d2ff, #3a7bd5); color: #fff; } | |
| .btn-primary:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 10px 25px rgba(0,210,255,0.4); } | |
| .btn-success { background: linear-gradient(135deg, #2ed573, #17a558); color: #fff; } | |
| .btn-danger { background: linear-gradient(135deg, #ff4757, #c0392b); color: #fff; } | |
| .btn:disabled { opacity: 0.5; cursor: not-allowed; } | |
| .status-indicator { | |
| display: inline-flex; align-items: center; gap: 8px; | |
| padding: 8px 15px; border-radius: 20px; font-size: 13px; font-weight: 600; | |
| margin-bottom: 15px; | |
| } | |
| .status-indicator.online { background: rgba(46,213,115,0.2); color: #2ed573; } | |
| .status-indicator.offline { background: rgba(255,71,87,0.2); color: #ff4757; } | |
| .status-indicator .dot { | |
| width: 8px; height: 8px; border-radius: 50%; | |
| animation: pulse 1.5s ease-in-out infinite; | |
| } | |
| .status-indicator.online .dot { background: #2ed573; } | |
| .status-indicator.offline .dot { background: #ff4757; } | |
| @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.3} } | |
| .stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 20px; } | |
| .stat-box { | |
| background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); | |
| border-radius: 12px; padding: 15px; text-align: center; | |
| } | |
| .stat-box .value { font-size: 24px; font-weight: 700; color: #00d2ff; } | |
| .stat-box .label { font-size: 11px; color: rgba(255,255,255,0.6); margin-top: 5px; } | |
| .log-container { | |
| background: rgba(0,0,0,0.3); border-radius: 12px; padding: 15px; | |
| height: 400px; overflow-y: auto; font-family: 'Courier New', monospace; | |
| font-size: 12px; line-height: 1.8; | |
| } | |
| .log-entry { | |
| padding: 8px 12px; margin-bottom: 8px; border-radius: 8px; | |
| border-right: 3px solid; animation: slideIn 0.3s ease; | |
| } | |
| @keyframes slideIn { from{opacity:0;transform:translateX(20px)} to{opacity:1;transform:translateX(0)} } | |
| .log-entry.info { background: rgba(0,210,255,0.1); border-color: #00d2ff; } | |
| .log-entry.success { background: rgba(46,213,115,0.1); border-color: #2ed573; } | |
| .log-entry.warning { background: rgba(255,193,7,0.1); border-color: #ffc107; } | |
| .log-entry.error { background: rgba(255,71,87,0.1); border-color: #ff4757; } | |
| .log-entry .time { color: rgba(255,255,255,0.5); font-size: 10px; } | |
| .log-entry .message { color: #fff; margin-top: 3px; word-break: break-word; } | |
| .features-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 15px; } | |
| .feature-card { | |
| background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); | |
| border-radius: 10px; padding: 12px; cursor: pointer; transition: all 0.3s; | |
| } | |
| .feature-card:hover { background: rgba(255,255,255,0.1); transform: translateY(-2px); } | |
| .feature-card.active { border-color: #2ed573; background: rgba(46,213,115,0.1); } | |
| .feature-card .icon { font-size: 24px; margin-bottom: 8px; } | |
| .feature-card .title { font-size: 13px; font-weight: 600; margin-bottom: 3px; } | |
| .feature-card .desc { font-size: 11px; color: rgba(255,255,255,0.5); } | |
| .tab-buttons { | |
| display: flex; gap: 8px; margin-bottom: 20px; | |
| border-bottom: 2px solid rgba(255,255,255,0.1); padding-bottom: 10px; | |
| } | |
| .tab-btn { | |
| padding: 8px 16px; border: none; background: transparent; | |
| color: rgba(255,255,255,0.6); font-size: 13px; font-weight: 600; | |
| cursor: pointer; border-radius: 8px; transition: all 0.3s; | |
| } | |
| .tab-btn.active { background: rgba(0,210,255,0.2); color: #00d2ff; } | |
| .tab-content { display: none; } | |
| .tab-content.active { display: block; animation: fadeIn 0.3s ease; } | |
| @keyframes fadeIn { from{opacity:0} to{opacity:1} } | |
| .keyword-list { max-height: 200px; overflow-y: auto; margin-top: 10px; } | |
| .keyword-item { | |
| display: flex; align-items: center; justify-content: space-between; | |
| padding: 10px; background: rgba(255,255,255,0.05); border-radius: 8px; | |
| margin-bottom: 8px; | |
| } | |
| .keyword-item .text { flex: 1; font-size: 13px; word-break: break-word; } | |
| .keyword-item .delete { | |
| background: rgba(255,71,87,0.2); border: none; color: #ff4757; | |
| width: 28px; height: 28px; border-radius: 50%; cursor: pointer; | |
| flex-shrink: 0; margin-right: 8px; | |
| } | |
| .add-keyword { display: flex; gap: 8px; margin-top: 10px; } | |
| .add-keyword input { flex: 1; } | |
| .add-keyword button { | |
| padding: 10px 20px; background: #00d2ff; border: none; | |
| border-radius: 8px; color: #fff; cursor: pointer; font-weight: 600; | |
| } | |
| .warning-banner { | |
| background: rgba(255,193,7,0.15); border: 1px solid rgba(255,193,7,0.4); | |
| border-radius: 10px; padding: 12px; margin-bottom: 15px; | |
| font-size: 12px; color: #ffc107; display: none; | |
| } | |
| .warning-banner.show { display: block; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="panel"> | |
| <h2><span class="icon">⚙️</span> پنل کنترل ربات</h2> | |
| <div class="warning-banner" id="corsWarning"> | |
| ⚠️ احتمالاً CORS درخواست رو بلاک میکنه. اگه کار نکرد، از سرور proxy استفاده کن. | |
| </div> | |
| <div class="status-indicator offline" id="statusIndicator"> | |
| <span class="dot"></span> | |
| <span id="statusText">آفلاین</span> | |
| </div> | |
| <div class="form-group"> | |
| <label>🔑 توکن API</label> | |
| <div class="input-with-toggle"> | |
| <input type="password" id="apiToken" placeholder="توکن را وارد کنید..."> | |
| <button type="button" class="toggle-vis" onclick="toggleTokenVis(this)">👁️</button> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label>👥 شناسه گروه (Chat ID)</label> | |
| <input type="text" id="chatId" placeholder="مثال: 279058397"> | |
| </div> | |
| <button class="btn btn-primary" id="startBtn" onclick="startBot()"> | |
| <span>▶️</span> شروع ربات | |
| </button> | |
| <button class="btn btn-danger" id="stopBtn" onclick="stopBot()" style="margin-top: 10px; display: none;"> | |
| <span>⏹️</span> توقف ربات | |
| </button> | |
| <div class="stats" style="margin-top: 20px;"> | |
| <div class="stat-box"><div class="value" id="messagesCount">0</div><div class="label">پیام دریافتی</div></div> | |
| <div class="stat-box"><div class="value" id="responsesCount">0</div><div class="label">پاسخ ارسال شده</div></div> | |
| <div class="stat-box"><div class="value" id="uptime">00:00</div><div class="label">زمان فعالیت</div></div> | |
| <div class="stat-box"><div class="value" id="errorsCount">0</div><div class="label">خطاها</div></div> | |
| </div> | |
| <h2 style="margin-top: 25px;"><span class="icon">✨</span> ویژگیها</h2> | |
| <div class="features-grid" id="featuresGrid"></div> | |
| </div> | |
| <div class="panel"> | |
| <h2><span class="icon">📊</span> لاگ فعالیتها</h2> | |
| <div class="tab-buttons"> | |
| <button class="tab-btn active" data-tab="logs">📜 لاگها</button> | |
| <button class="tab-btn" data-tab="settings">⚙️ تنظیمات</button> | |
| <button class="tab-btn" data-tab="keywords">🔑 کلمات کلیدی</button> | |
| </div> | |
| <div class="tab-content active" id="tab-logs"> | |
| <div class="log-container" id="logContainer"></div> | |
| </div> | |
| <div class="tab-content" id="tab-settings"> | |
| <div class="form-group"> | |
| <label>پیام خوشآمدگویی</label> | |
| <textarea id="welcomeMessage" rows="3">👋 سلام {name} عزیز! | |
| به گروه ما خوش آمدی 🎉</textarea> | |
| </div> | |
| <div class="form-group"> | |
| <label>پاسخ به سلام</label> | |
| <input type="text" id="greetingResponse" value="سلام علیکم 🙏"> | |
| </div> | |
| <div class="form-group"> | |
| <label>فاصله بررسی (میلیثانیه) - حداقل 3000</label> | |
| <input type="number" id="pollInterval" value="3000" min="3000" step="500"> | |
| </div> | |
| <button class="btn btn-success" onclick="saveSettings()"> | |
| <span>💾</span> ذخیره تنظیمات | |
| </button> | |
| </div> | |
| <div class="tab-content" id="tab-keywords"> | |
| <h3 style="font-size: 14px; margin-bottom: 10px;">🚫 کلمات ممنوعه</h3> | |
| <div class="keyword-list" id="bannedWordsList"></div> | |
| <div class="add-keyword"> | |
| <input type="text" id="newBannedWord" placeholder="کلمه جدید..."> | |
| <button onclick="addBannedWord()">افزودن</button> | |
| </div> | |
| <h3 style="font-size: 14px; margin-top: 25px; margin-bottom: 10px;">💡 پاسخهای خودکار</h3> | |
| <div class="keyword-list" id="autoResponsesList"></div> | |
| <div class="add-keyword"> | |
| <input type="text" id="newAutoKeyword" placeholder="کلمه..."> | |
| <input type="text" id="newAutoResponse" placeholder="پاسخ..."> | |
| <button onclick="addAutoResponse()">افزودن</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| ; | |
| // ===== تنظیمات پیشفرض ===== | |
| const DEFAULTS = { | |
| token: '', chatId: '', lastUpdateId: 0, pollInterval: 3000, | |
| welcomeMessage: '👋 سلام {name} عزیز!\nبه گروه ما خوش آمدی 🎉', | |
| greetingResponse: 'سلام علیکم 🙏', | |
| features: { welcome:true, greeting:true, google:true, help:true, time:true, quote:true, ping:true, filter:true }, | |
| bannedWords: [], | |
| autoResponses: { 'سلام': 'سلام علیکم 🙏', 'صبح بخیر': 'صبح شما هم بخیر ☀️' }, | |
| stats: { messages: 0, responses: 0, errors: 0 } | |
| }; | |
| const FEATURES_META = [ | |
| { id: 'welcome', icon: '👋', title: 'خوشآمدگویی', desc: 'پیام برای اعضای جدید' }, | |
| { id: 'greeting', icon: '🙏', title: 'پاسخ به سلام', desc: 'پاسخ "سلام علیکم"' }, | |
| { id: 'google', icon: '🔍', title: 'جستجوی گوگل', desc: 'دستور /google' }, | |
| { id: 'help', icon: '❓', title: 'راهنما', desc: 'دستور /help' }, | |
| { id: 'time', icon: '🕐', title: 'ساعت و تاریخ', desc: 'دستور /time' }, | |
| { id: 'quote', icon: '💬', title: 'نقل قول', desc: 'دستور /quote' }, | |
| { id: 'ping', icon: '🏓', title: 'پینگ', desc: 'دستور /ping' }, | |
| { id: 'filter', icon: '🚫', title: 'فیلتر کلمات', desc: 'حذف پیام نامناسب' } | |
| ]; | |
| const QUOTES = [ | |
| '💡 "تنها راه انجام کار بزرگ، عشق به آن است." - استیو جابز', | |
| '🌟 "موفقیت نهایی نیست، شکست کشنده نیست، شجاعت ادامه دادن مهم است."', | |
| '🚀 "آینده به کسانی تعلق دارد که به رویاهایشان ایمان دارند."', | |
| '💪 "هر روز یک فرصت جدید برای تغییر است."', | |
| '🎯 "تمرکز یعنی نه گفتن به صد ایده خوب دیگر."', | |
| '🌈 "بعد از هر شب تاریک، صبح روشن در راه است."' | |
| ]; | |
| // ===== وضعیت ربات ===== | |
| let bot = { | |
| config: { ...DEFAULTS }, | |
| running: false, | |
| startTime: null, | |
| pollTimer: null, | |
| uptimeTimer: null | |
| }; | |
| // ===== ابزارهای کمکی ===== | |
| function escapeHtml(str) { | |
| const div = document.createElement('div'); | |
| div.textContent = str; | |
| return div.innerHTML; | |
| } | |
| function escapeMarkdown(str) { | |
| return str.replace(/([_*`\[\]()~>#+\-=|{}.!])/g, '\\$1'); | |
| } | |
| function $(id) { return document.getElementById(id); } | |
| function loadConfig() { | |
| try { | |
| const saved = localStorage.getItem('eitaBotConfig_v2'); | |
| if (saved) { | |
| const parsed = JSON.parse(saved); | |
| bot.config = { ...DEFAULTS, ...parsed, features: { ...DEFAULTS.features, ...(parsed.features||{}) }, stats: { ...DEFAULTS.stats, ...(parsed.stats||{}) } }; | |
| } | |
| } catch (e) { console.error('Load error:', e); } | |
| } | |
| function saveConfig() { | |
| try { | |
| localStorage.setItem('eitaBotConfig_v2', JSON.stringify(bot.config)); | |
| } catch (e) { addLog('error', '❌ خطا در ذخیره: ' + e.message); } | |
| } | |
| // ===== UI ===== | |
| function toggleTokenVis(btn) { | |
| const input = $('apiToken'); | |
| if (input.type === 'password') { input.type = 'text'; btn.textContent = '🙈'; } | |
| else { input.type = 'password'; btn.textContent = '👁️'; } | |
| } | |
| function renderFeatures() { | |
| const grid = $('featuresGrid'); | |
| grid.innerHTML = FEATURES_META.map(f => ` | |
| <div class="feature-card ${bot.config.features[f.id] ? 'active' : ''}" data-feature="${f.id}"> | |
| <div class="icon">${f.icon}</div> | |
| <div class="title">${f.title}</div> | |
| <div class="desc">${f.desc}</div> | |
| </div> | |
| `).join(''); | |
| grid.querySelectorAll('.feature-card').forEach(card => { | |
| card.addEventListener('click', () => { | |
| const id = card.dataset.feature; | |
| bot.config.features[id] = !bot.config.features[id]; | |
| card.classList.toggle('active'); | |
| saveConfig(); | |
| addLog('info', `${bot.config.features[id] ? '✅' : '❌'} ${FEATURES_META.find(f=>f.id===id).title}`); | |
| }); | |
| }); | |
| } | |
| function renderBannedWords() { | |
| const list = $('bannedWordsList'); | |
| list.innerHTML = ''; | |
| bot.config.bannedWords.forEach((word, i) => { | |
| const item = document.createElement('div'); | |
| item.className = 'keyword-item'; | |
| const span = document.createElement('span'); | |
| span.className = 'text'; | |
| span.textContent = word; | |
| const btn = document.createElement('button'); | |
| btn.className = 'delete'; | |
| btn.textContent = '✕'; | |
| btn.onclick = () => { | |
| bot.config.bannedWords.splice(i, 1); | |
| renderBannedWords(); | |
| saveConfig(); | |
| addLog('warning', '🗑️ حذف: ' + word); | |
| }; | |
| item.appendChild(span); | |
| item.appendChild(btn); | |
| list.appendChild(item); | |
| }); | |
| } | |
| function renderAutoResponses() { | |
| const list = $('autoResponsesList'); | |
| list.innerHTML = ''; | |
| Object.entries(bot.config.autoResponses).forEach(([k, v]) => { | |
| const item = document.createElement('div'); | |
| item.className = 'keyword-item'; | |
| const span = document.createElement('span'); | |
| span.className = 'text'; | |
| span.innerHTML = `<strong>${escapeHtml(k)}:</strong> ${escapeHtml(v)}`; | |
| const btn = document.createElement('button'); | |
| btn.className = 'delete'; | |
| btn.textContent = '✕'; | |
| btn.onclick = () => { | |
| delete bot.config.autoResponses[k]; | |
| renderAutoResponses(); | |
| saveConfig(); | |
| addLog('warning', '🗑️ حذف: ' + k); | |
| }; | |
| item.appendChild(span); | |
| item.appendChild(btn); | |
| list.appendChild(item); | |
| }); | |
| } | |
| function addBannedWord() { | |
| const input = $('newBannedWord'); | |
| const word = input.value.trim(); | |
| if (word && !bot.config.bannedWords.includes(word)) { | |
| bot.config.bannedWords.push(word); | |
| input.value = ''; | |
| renderBannedWords(); | |
| saveConfig(); | |
| addLog('success', '✅ اضافه: ' + word); | |
| } | |
| } | |
| function addAutoResponse() { | |
| const k = $('newAutoKeyword').value.trim(); | |
| const v = $('newAutoResponse').value.trim(); | |
| if (k && v) { | |
| bot.config.autoResponses[k] = v; | |
| $('newAutoKeyword').value = ''; | |
| $('newAutoResponse').value = ''; | |
| renderAutoResponses(); | |
| saveConfig(); | |
| addLog('success', '✅ پاسخ خودکار: ' + k); | |
| } | |
| } | |
| function addLog(type, message) { | |
| const container = $('logContainer'); | |
| const entry = document.createElement('div'); | |
| entry.className = `log-entry ${type}`; | |
| const timeDiv = document.createElement('div'); | |
| timeDiv.className = 'time'; | |
| timeDiv.textContent = new Date().toLocaleTimeString('fa-IR'); | |
| const msgDiv = document.createElement('div'); | |
| msgDiv.className = 'message'; | |
| msgDiv.textContent = message; // ✅ امن - بدون innerHTML | |
| entry.appendChild(timeDiv); | |
| entry.appendChild(msgDiv); | |
| container.insertBefore(entry, container.firstChild); | |
| while (container.children.length > 100) container.removeChild(container.lastChild); | |
| } | |
| function updateStats() { | |
| $('messagesCount').textContent = bot.config.stats.messages; | |
| $('responsesCount').textContent = bot.config.stats.responses; | |
| $('errorsCount').textContent = bot.config.stats.errors; | |
| } | |
| function updateStatus(online) { | |
| $('statusIndicator').className = 'status-indicator ' + (online ? 'online' : 'offline'); | |
| $('statusText').textContent = online ? 'آنلاین' : 'آفلاین'; | |
| } | |
| function switchTab(tabName, btnEl) { | |
| document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); | |
| document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); | |
| btnEl.classList.add('active'); | |
| $('tab-' + tabName).classList.add('active'); | |
| } | |
| function saveSettings() { | |
| const interval = Math.max(3000, parseInt($('pollInterval').value) || 3000); | |
| bot.config.pollInterval = interval; | |
| $('pollInterval').value = interval; | |
| bot.config.welcomeMessage = $('welcomeMessage').value; | |
| bot.config.greetingResponse = $('greetingResponse').value; | |
| saveConfig(); | |
| addLog('success', '✅ تنظیمات ذخیره شد'); | |
| } | |
| // ===== API ===== | |
| async function apiCall(method, params) { | |
| const controller = new AbortController(); | |
| const timeout = setTimeout(() => controller.abort(), 15000); // ✅ timeout 15s | |
| try { | |
| // ساختار واقعی API ایتایار | |
| const url = 'https://eitaayar.ir/api/app/' + method; | |
| const body = { token: bot.config.token, ...params }; | |
| const response = await fetch(url, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, | |
| body: JSON.stringify(body), | |
| signal: controller.signal | |
| }); | |
| clearTimeout(timeout); | |
| if (!response.ok) throw new Error('HTTP ' + response.status); | |
| const data = await response.json(); | |
| if (data.status === 'error' || data.ok === false) { | |
| throw new Error(data.error || data.description || 'خطای API'); | |
| } | |
| return data; | |
| } catch (e) { | |
| clearTimeout(timeout); | |
| if (e.name === 'AbortError') throw new Error('Timeout - سرور جواب نداد'); | |
| if (e.message.includes('Failed to fetch')) { | |
| $('corsWarning').classList.add('show'); | |
| throw new Error('CORS یا خطای شبکه - نیاز به proxy'); | |
| } | |
| throw e; | |
| } | |
| } | |
| async function sendMessage(chatId, text) { | |
| try { | |
| const result = await apiCall('sendMessage', { | |
| chat_id: String(chatId), | |
| text: text | |
| // parse_mode حذف شد تا مشکل Markdown حل بشه | |
| }); | |
| bot.config.stats.responses++; | |
| updateStats(); | |
| return true; | |
| } catch (e) { | |
| bot.config.stats.errors++; | |
| updateStats(); | |
| addLog('error', '❌ ارسال: ' + e.message); | |
| return false; | |
| } | |
| } | |
| // ===== منطق ربات ===== | |
| async function startBot() { | |
| const token = $('apiToken').value.trim(); | |
| const chatId = $('chatId').value.trim(); | |
| if (!token || !chatId) { addLog('error', '❌ توکن و شناسه گروه الزامی است'); return; } | |
| bot.config.token = token; | |
| bot.config.chatId = chatId; | |
| bot.running = true; | |
| bot.startTime = Date.now(); | |
| $('startBtn').style.display = 'none'; | |
| $('stopBtn').style.display = 'block'; | |
| updateStatus(true); | |
| addLog('success', '🚀 ربات شروع شد'); | |
| try { | |
| const me = await apiCall('getMe', {}); | |
| addLog('success', '✅ اتصال موفق'); | |
| } catch (e) { | |
| addLog('error', '❌ اتصال: ' + e.message); | |
| stopBot(); | |
| return; | |
| } | |
| saveConfig(); | |
| pollLoop(); | |
| bot.uptimeTimer = setInterval(() => { | |
| if (bot.startTime) $('uptime').textContent = formatUptime(Date.now() - bot.startTime); | |
| }, 1000); | |
| } | |
| function stopBot() { | |
| bot.running = false; | |
| if (bot.pollTimer) clearTimeout(bot.pollTimer); | |
| if (bot.uptimeTimer) clearInterval(bot.uptimeTimer); | |
| $('startBtn').style.display = 'block'; | |
| $('stopBtn').style.display = 'none'; | |
| updateStatus(false); | |
| addLog('warning', '⏹️ ربات متوقف شد'); | |
| saveConfig(); | |
| } | |
| async function pollLoop() { | |
| if (!bot.running) return; | |
| try { | |
| await pollMessages(); | |
| } catch (e) { | |
| bot.config.stats.errors++; | |
| updateStats(); | |
| addLog('error', '❌ Poll: ' + e.message); | |
| } | |
| if (bot.running) bot.pollTimer = setTimeout(pollLoop, bot.config.pollInterval); | |
| } | |
| async function pollMessages() { | |
| const data = await apiCall('getUpdates', { | |
| offset: bot.config.lastUpdateId + 1, | |
| limit: 100 | |
| }); | |
| const updates = data.result || []; | |
| for (const update of updates) { | |
| bot.config.lastUpdateId = update.update_id; | |
| bot.config.stats.messages++; | |
| updateStats(); | |
| if (update.message) await processMessage(update.message); | |
| } | |
| if (updates.length) saveConfig(); // ✅ ذخیره offset | |
| } | |
| async function processMessage(msg) { | |
| const text = msg.text || msg.caption || ''; | |
| const chatId = msg.chat?.id; | |
| const userName = msg.from?.first_name || msg.from?.username || 'کاربر'; | |
| if (!chatId) return; | |
| addLog('info', `📨 ${userName}: ${text.substring(0, 50)}`); | |
| // فیلتر | |
| if (bot.config.features.filter && text && shouldFilter(text)) { | |
| addLog('warning', '🚫 فیلتر: ' + userName); | |
| try { | |
| await apiCall('deleteMessage', { chat_id: String(chatId), message_id: msg.message_id }); | |
| await sendMessage(chatId, `⚠️ ${userName}، لطفاً کلمات مناسب استفاده کنید.`); | |
| } catch (e) { addLog('error', 'حذف نشد: ' + e.message); } | |
| return; | |
| } | |
| // دستورات | |
| if (text.startsWith('/')) { | |
| await processCommand(text, chatId, userName); | |
| return; | |
| } | |
| // پاسخ خودکار | |
| for (const [k, v] of Object.entries(bot.config.autoResponses)) { | |
| if (text.includes(k)) { | |
| await sendMessage(chatId, v); | |
| addLog('success', '💬 خودکار: ' + k); | |
| return; | |
| } | |
| } | |
| // سلام | |
| if (bot.config.features.greeting && /سلام|درود|hello|hi/i.test(text)) { | |
| await sendMessage(chatId, bot.config.greetingResponse); | |
| addLog('success', '🙏 پاسخ سلام'); | |
| } | |
| } | |
| async function processCommand(text, chatId, userName) { | |
| // ✅ پشتیبانی از /command@botname | |
| const parts = text.split(' ')[0].toLowerCase().split('@')[0]; | |
| const args = text.substring(text.indexOf(' ') + 1).trim(); | |
| switch (parts) { | |
| case '/help': case '/start': | |
| if (!bot.config.features.help) return; | |
| await sendMessage(chatId, `🤖 دستورات ربات: | |
| 👋 /help - راهنما | |
| 🔍 /google [عبارت] - جستجو | |
| 🕐 /time - ساعت | |
| 💬 /quote - نقل قول | |
| 🏓 /ping - پینگ | |
| 📊 /info - آمار`); | |
| break; | |
| case '/google': | |
| if (!bot.config.features.google) return; | |
| if (!args) { await sendMessage(chatId, '❗ مثال: /google هوش مصنوعی'); return; } | |
| await sendMessage(chatId, `🔍 جستجو: ${args}\n\n🔗 https://www.google.com/search?q=${encodeURIComponent(args)}`); | |
| break; | |
| case '/time': | |
| if (!bot.config.features.time) return; | |
| await sendMessage(chatId, '🕐 ' + new Date().toLocaleString('fa-IR')); | |
| break; | |
| case '/quote': | |
| if (!bot.config.features.quote) return; | |
| await sendMessage(chatId, QUOTES[Math.floor(Math.random() * QUOTES.length)]); | |
| break; | |
| case '/ping': | |
| if (!bot.config.features.ping) return; | |
| const t = Date.now(); | |
| await sendMessage(chatId, '🏓 پینگ...'); | |
| await sendMessage(chatId, `🏓 پنگ!\n⏱️ ${Date.now() - t}ms`); | |
| break; | |
| case '/info': | |
| await sendMessage(chatId, `📊 آمار: | |
| ⏱️ فعالیت: ${formatUptime(Date.now() - (bot.startTime||Date.now()))} | |
| 📨 دریافتی: ${bot.config.stats.messages} | |
| 💬 پاسخ: ${bot.config.stats.responses} | |
| ❌ خطا: ${bot.config.stats.errors}`); | |
| break; | |
| } | |
| } | |
| function shouldFilter(text) { | |
| const lower = text.toLowerCase(); | |
| return bot.config.bannedWords.some(w => lower.includes(w.toLowerCase())); | |
| } | |
| function formatUptime(ms) { | |
| const s = Math.floor(ms / 1000); | |
| const m = Math.floor(s / 60); | |
| const h = Math.floor(m / 60); | |
| if (h > 0) return `${h}h ${m%60}m`; | |
| if (m > 0) return `${m}m ${s%60}s`; | |
| return `${s}s`; | |
| } | |
| // ===== راهاندازی ===== | |
| window.addEventListener('load', () => { | |
| loadConfig(); | |
| $('apiToken').value = bot.config.token || ''; | |
| $('chatId').value = bot.config.chatId || ''; | |
| $('pollInterval').value = bot.config.pollInterval; | |
| $('welcomeMessage').value = bot.config.welcomeMessage; | |
| $('greetingResponse').value = bot.config.greetingResponse; | |
| renderFeatures(); | |
| renderBannedWords(); | |
| renderAutoResponses(); | |
| updateStats(); | |
| // تبها - ✅ بدون event global | |
| document.querySelectorAll('.tab-btn').forEach(btn => { | |
| btn.addEventListener('click', () => switchTab(btn.dataset.tab, btn)); | |
| }); | |
| // Enter برای افزودن کلمات | |
| $('newBannedWord').addEventListener('keypress', e => { if (e.key === 'Enter') addBannedWord(); }); | |
| $('newAutoResponse').addEventListener('keypress', e => { if (e.key === 'Enter') addAutoResponse(); }); | |
| $('newAutoKeyword').addEventListener('keypress', e => { if (e.key === 'Enter') $('newAutoResponse').focus(); }); | |
| addLog('info', '✅ سیستم آماده است'); | |
| }); | |
| // ✅ قبل از خروج فقط ذخیره، نه stop | |
| window.addEventListener('beforeunload', saveConfig); | |
| </script> | |
| </body> | |
| </html> |