Team Ai
Apppublic

VisionByte/replit-host-bot

sourceHugging Facemitupdated 7mo agoView on Hugging Face
0likes
bot.py811 linesDownload Raw Back to root
1import logging2import json3import os4import re5from datetime import datetime6from telegram import (7    Update, InlineKeyboardButton, InlineKeyboardMarkup,8    BotCommand9)10from telegram.ext import (11    Application, CommandHandler, MessageHandler,12    CallbackQueryHandler, ContextTypes, ConversationHandler, filters13)14from telegram.constants import ParseMode15 16# ─── Config ───────────────────────────────────────────────────────────────────17BOT_TOKEN = "8642217017:AAEHsExfWGqxNUFgOx6bXGuyNtABAdvJBV0"18ADMIN_ID = 877922051819DB_FILE = "database.json"20 21logging.basicConfig(22    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",23    level=logging.INFO24)25logger = logging.getLogger(__name__)26 27# ─── Conversation States ───────────────────────────────────────────────────────28WAITING_TOKEN, WAITING_CODE, WAITING_BOT_NAME, WAITING_BROADCAST = range(4)29 30# ─── Database ──────────────────────────────────────────────────────────────────31def load_db():32    if not os.path.exists(DB_FILE):33        return {"users": {}, "bots": {}, "stats": {"total_hosted": 0}}34    with open(DB_FILE, "r", encoding="utf-8") as f:35        return json.load(f)36 37def save_db(db):38    with open(DB_FILE, "w", encoding="utf-8") as f:39        json.dump(db, f, ensure_ascii=False, indent=2)40 41def register_user(user_id: int, username: str, full_name: str):42    db = load_db()43    uid = str(user_id)44    if uid not in db["users"]:45        db["users"][uid] = {46            "username": username,47            "full_name": full_name,48            "joined": datetime.now().isoformat(),49            "bots": [],50            "banned": False51        }52        save_db(db)53    return db["users"][uid]54 55def is_banned(user_id: int) -> bool:56    db = load_db()57    uid = str(user_id)58    return db["users"].get(uid, {}).get("banned", False)59 60# ─── Helpers ───────────────────────────────────────────────────────────────────61def validate_token(token: str) -> bool:62    return bool(re.match(r"^\d{8,12}:[A-Za-z0-9_-]{35}$", token.strip()))63 64def back_btn(callback="main_menu"):65    return InlineKeyboardMarkup([[66        InlineKeyboardButton("🔙 رجوع | Back", callback_data=callback)67    ]])68 69def generate_replit_files(bot_token: str, bot_code: str, bot_name: str) -> dict:70    """Generate all Replit config files"""71 72    replit_nix = '''{ pkgs }: {73  deps = [74    pkgs.python31175    pkgs.python311Packages.pip76  ];77}'''78 79    replit_config = f'''run = "python main.py"80entrypoint = "main.py"81 82[nix]83channel = "stable-23_11"84 85[deployment]86run = ["sh", "-c", "python main.py"]87deploymentTarget = "cloudrun"88 89[[ports]]90localPort = 808091externalPort = 8092'''93 94    requirements = '''python-telegram-bot==21.695requests96'''97 98    keep_alive = '''from flask import Flask99from threading import Thread100 101app = Flask("")102 103@app.route("/")104def home():105    return "Bot is alive! 🤖"106 107def run():108    app.run(host="0.0.0.0", port=8080)109 110def keep_alive():111    t = Thread(target=run)112    t.start()113'''114 115    main_py = f'''# ═══════════════════════════════════════════116#   Bot: {bot_name}117#   Hosted via @ReplitHostBot118#   Generated automatically119# ═══════════════════════════════════════════120 121import os122from keep_alive import keep_alive123 124# Keep the bot alive on Replit125keep_alive()126 127# ─── Your Bot Code Below ───────────────────128{bot_code}129'''130 131    return {132        "main.py": main_py,133        "keep_alive.py": keep_alive,134        "requirements.txt": requirements,135        ".replit": replit_config,136        "replit.nix": replit_nix,137    }138 139# ─── /start ────────────────────────────────────────────────────────────────────140async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):141    user = update.effective_user142    if is_banned(user.id):143        await update.message.reply_text("🚫 تم حظرك من استخدام البوت.\n🚫 You are banned from using this bot.")144        return145 146    register_user(user.id, user.username or "", user.full_name or "")147 148    text = (149        "╔══════════════════════════════╗\n"150        "║   🚀 *Replit Host Bot*         ║\n"151        "╚══════════════════════════════╝\n\n"152        "🇸🇦 *مرحباً بك في بوت الاستضافة المجانية!*\n"153        "استضف بوت تيليجرام الخاص بك مجاناً على Replit في دقائق.\n\n"154        "🇬🇧 *Welcome to the Free Hosting Bot!*\n"155        "Host your Telegram bot on Replit for free in minutes.\n\n"156        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"157        "📌 *ما الذي يقدمه هذا البوت؟*\n"158        "• توليد ملفات Replit تلقائياً\n"159        "• دليل خطوة بخطوة مصوّر\n"160        "• إدارة بوتاتك المسجّلة\n\n"161        "📌 *What does this bot offer?*\n"162        "• Auto-generate Replit config files\n"163        "• Step-by-step visual guide\n"164        "• Manage your registered bots"165    )166 167    keyboard = InlineKeyboardMarkup([168        [InlineKeyboardButton("🚀 استضف بوت | Host a Bot", callback_data="host_bot")],169        [InlineKeyboardButton("📋 بوتاتي | My Bots", callback_data="my_bots"),170         InlineKeyboardButton("📖 دليل | Guide", callback_data="guide")],171        [InlineKeyboardButton("ℹ️ عن البوت | About", callback_data="about"),172         InlineKeyboardButton("📞 دعم | Support", callback_data="support")],173    ])174 175    await update.message.reply_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)176 177# ─── Main Menu Callback ────────────────────────────────────────────────────────178async def main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):179    query = update.callback_query180    await query.answer()181    user = update.effective_user182    if is_banned(user.id):183        await query.edit_message_text("🚫 تم حظرك.\n🚫 You are banned.")184        return185 186    text = (187        "╔══════════════════════════════╗\n"188        "║   🚀 *Replit Host Bot*         ║\n"189        "╚══════════════════════════════╝\n\n"190        "🇸🇦 *مرحباً بك في بوت الاستضافة المجانية!*\n\n"191        "🇬🇧 *Welcome to the Free Hosting Bot!*"192    )193    keyboard = InlineKeyboardMarkup([194        [InlineKeyboardButton("🚀 استضف بوت | Host a Bot", callback_data="host_bot")],195        [InlineKeyboardButton("📋 بوتاتي | My Bots", callback_data="my_bots"),196         InlineKeyboardButton("📖 دليل | Guide", callback_data="guide")],197        [InlineKeyboardButton("ℹ️ عن البوت | About", callback_data="about"),198         InlineKeyboardButton("📞 دعم | Support", callback_data="support")],199    ])200    await query.edit_message_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)201 202# ─── Host Bot Flow ─────────────────────────────────────────────────────────────203async def host_bot_start(update: Update, context: ContextTypes.DEFAULT_TYPE):204    query = update.callback_query205    await query.answer()206 207    text = (208        "🚀 *استضافة بوت جديد | Host a New Bot*\n\n"209        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"210        "🇸🇦 *الخطوة 1/3:* أرسل توكن البوت\n"211        "احصل عليه من @BotFather\n\n"212        "🇬🇧 *Step 1/3:* Send your bot token\n"213        "Get it from @BotFather\n\n"214        "📌 *مثال | Example:*\n"215        "`1234567890:ABCdefGHIjklMNOpqrSTUvwxYZ`"216    )217    await query.edit_message_text(text, reply_markup=back_btn(), parse_mode=ParseMode.MARKDOWN)218    return WAITING_TOKEN219 220async def receive_token(update: Update, context: ContextTypes.DEFAULT_TYPE):221    user = update.effective_user222    if is_banned(user.id):223        return ConversationHandler.END224 225    token = update.message.text.strip()226 227    if not validate_token(token):228        await update.message.reply_text(229            "❌ *توكن غير صحيح | Invalid Token*\n\n"230            "🇸🇦 تأكد من نسخ التوكن كاملاً من @BotFather\n"231            "🇬🇧 Make sure to copy the full token from @BotFather\n\n"232            "🔄 أرسل التوكن مجدداً | Send the token again:",233            parse_mode=ParseMode.MARKDOWN234        )235        return WAITING_TOKEN236 237    context.user_data["pending_token"] = token238 239    text = (240        "✅ *تم استلام التوكن | Token Received*\n\n"241        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"242        "🇸🇦 *الخطوة 2/3:* أرسل اسماً للبوت\n"243        "(للتعريف فقط - مثال: My Echo Bot)\n\n"244        "🇬🇧 *Step 2/3:* Send a name for the bot\n"245        "(For identification only - e.g. My Echo Bot)"246    )247    await update.message.reply_text(text, reply_markup=back_btn(), parse_mode=ParseMode.MARKDOWN)248    return WAITING_BOT_NAME249 250async def receive_bot_name(update: Update, context: ContextTypes.DEFAULT_TYPE):251    name = update.message.text.strip()252    if len(name) > 50:253        await update.message.reply_text("❌ الاسم طويل جداً (max 50 chars). أرسل اسماً أقصر:")254        return WAITING_BOT_NAME255 256    context.user_data["pending_name"] = name257 258    text = (259        f"✅ *الاسم: {name}*\n\n"260        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"261        "🇸🇦 *الخطوة 3/3:* أرسل كود البوت\n"262        "• أرسله كملف `.py` أو نص عادي\n"263        "• تأكد أن الكود يعمل بشكل صحيح\n\n"264        "🇬🇧 *Step 3/3:* Send your bot code\n"265        "• Send as `.py` file or plain text\n"266        "• Make sure the code works correctly\n\n"267        "⚠️ *ملاحظة | Note:*\n"268        "لا تضع التوكن داخل الكود — سيُضاف تلقائياً\n"269        "Don't put the token in code — it will be added automatically"270    )271    await update.message.reply_text(text, reply_markup=back_btn(), parse_mode=ParseMode.MARKDOWN)272    return WAITING_CODE273 274async def receive_code(update: Update, context: ContextTypes.DEFAULT_TYPE):275    user = update.effective_user276    bot_code = ""277 278    # Accept file or text279    if update.message.document:280        if not update.message.document.file_name.endswith(".py"):281            await update.message.reply_text("❌ أرسل ملف `.py` فقط | Send only `.py` files")282            return WAITING_CODE283        file = await update.message.document.get_file()284        file_bytes = await file.download_as_bytearray()285        bot_code = file_bytes.decode("utf-8")286    elif update.message.text:287        bot_code = update.message.text.strip()288    else:289        await update.message.reply_text("❌ أرسل الكود كنص أو ملف .py | Send code as text or .py file")290        return WAITING_CODE291 292    token = context.user_data.get("pending_token")293    bot_name = context.user_data.get("pending_name", "My Bot")294 295    # Generate files296    files = generate_replit_files(token, bot_code, bot_name)297 298    # Save to DB299    db = load_db()300    uid = str(user.id)301    bot_id = f"bot_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"302 303    db["bots"][bot_id] = {304        "owner_id": user.id,305        "name": bot_name,306        "token_preview": token[:12] + "...",307        "created": datetime.now().isoformat(),308        "status": "pending_deploy"309    }310    if uid not in db["users"]:311        db["users"][uid] = {"bots": [], "banned": False}312    db["users"][uid].setdefault("bots", []).append(bot_id)313    db["stats"]["total_hosted"] = db["stats"].get("total_hosted", 0) + 1314    save_db(db)315 316    # Send each file317    await update.message.reply_text(318        "✅ *تم توليد الملفات بنجاح! | Files generated successfully!*\n\n"319        "📂 سأرسل لك الآن كل الملفات المطلوبة:\n"320        "📂 I'll now send you all required files:",321        parse_mode=ParseMode.MARKDOWN322    )323 324    file_descriptions = {325        "main.py": "📄 *main.py* — الكود الرئيسي للبوت | Main bot code",326        "keep_alive.py": "📄 *keep_alive.py* — للإبقاء على البوت حياً | Keeps bot alive",327        "requirements.txt": "📄 *requirements.txt* — المكتبات المطلوبة | Required libraries",328        ".replit": "⚙️ *.replit* — إعدادات Replit | Replit config",329        "replit.nix": "⚙️ *replit.nix* — بيئة Python | Python environment",330    }331 332    for filename, content in files.items():333        desc = file_descriptions.get(filename, f"📄 *{filename}*")334        await update.message.reply_text(desc, parse_mode=ParseMode.MARKDOWN)335 336        # Send as file337        import io338        file_obj = io.BytesIO(content.encode("utf-8"))339        file_obj.name = filename340        await update.message.reply_document(document=file_obj, filename=filename)341 342    # Send guide343    guide_text = (344        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"345        "📖 *خطوات الرفع على Replit | Upload Steps*\n"346        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"347        "1️⃣ افتح [replit.com](https://replit.com) وسجّل دخول\n"348        "   *Open replit.com and sign in*\n\n"349        "2️⃣ اضغط *Create Repl* ← اختر *Python*\n"350        "   *Click Create Repl → Choose Python*\n\n"351        "3️⃣ احذف الملفات الموجودة كلها\n"352        "   *Delete all existing files*\n\n"353        "4️⃣ ارفع الملفات اللي بعثتهالك (Import Files)\n"354        "   *Upload the files I sent you*\n\n"355        "5️⃣ اضغط *Run* ▶️\n"356        "   *Click Run ▶️*\n\n"357        "6️⃣ 🎉 البوت شغّال!\n"358        "   *🎉 Your bot is running!*\n\n"359        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"360        "💡 *نصيحة | Tip:*\n"361        "للإبقاء على البوت 24/7، استخدم [UptimeRobot](https://uptimerobot.com) مجاناً\n"362        "To keep bot 24/7, use UptimeRobot for free\n\n"363        "❓ مشكلة؟ اضغط /support"364    )365 366    keyboard = InlineKeyboardMarkup([367        [InlineKeyboardButton("📋 بوتاتي | My Bots", callback_data="my_bots")],368        [InlineKeyboardButton("🏠 القائمة الرئيسية | Main Menu", callback_data="main_menu")]369    ])370    await update.message.reply_text(guide_text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN,371                                    disable_web_page_preview=True)372 373    context.user_data.clear()374    return ConversationHandler.END375 376async def cancel_host(update: Update, context: ContextTypes.DEFAULT_TYPE):377    context.user_data.clear()378    if update.callback_query:379        await update.callback_query.answer()380        await main_menu_callback(update, context)381    return ConversationHandler.END382 383# ─── My Bots ───────────────────────────────────────────────────────────────────384async def my_bots(update: Update, context: ContextTypes.DEFAULT_TYPE):385    query = update.callback_query386    await query.answer()387    user = update.effective_user388 389    db = load_db()390    uid = str(user.id)391    user_bots = db["users"].get(uid, {}).get("bots", [])392 393    if not user_bots:394        text = (395            "📋 *بوتاتي | My Bots*\n\n"396            "🇸🇦 لا يوجد بوتات مسجّلة بعد.\n"397            "🇬🇧 No bots registered yet.\n\n"398            "اضغط 🚀 لاستضافة أول بوت!"399        )400        keyboard = InlineKeyboardMarkup([401            [InlineKeyboardButton("🚀 استضف بوت | Host a Bot", callback_data="host_bot")],402            [InlineKeyboardButton("🔙 رجوع | Back", callback_data="main_menu")]403        ])404        await query.edit_message_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)405        return406 407    text = "📋 *بوتاتي المسجّلة | My Registered Bots*\n\n"408    keyboard_buttons = []409 410    for bot_id in user_bots:411        bot = db["bots"].get(bot_id)412        if bot:413            created = bot["created"][:10]414            text += f"🤖 *{bot['name']}*\n"415            text += f"   📅 {created} | 🔑 `{bot['token_preview']}`\n\n"416            keyboard_buttons.append([417                InlineKeyboardButton(f"🗑️ حذف {bot['name']}", callback_data=f"del_{bot_id}")418            ])419 420    keyboard_buttons.append([InlineKeyboardButton("🔙 رجوع | Back", callback_data="main_menu")])421    await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard_buttons),422                                  parse_mode=ParseMode.MARKDOWN)423 424async def delete_bot_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):425    query = update.callback_query426    await query.answer()427    bot_id = query.data.replace("del_", "")428    user = update.effective_user429 430    db = load_db()431    uid = str(user.id)432 433    if bot_id in db["bots"] and db["bots"][bot_id]["owner_id"] == user.id:434        del db["bots"][bot_id]435        if uid in db["users"] and bot_id in db["users"][uid].get("bots", []):436            db["users"][uid]["bots"].remove(bot_id)437        save_db(db)438        await query.answer("✅ تم الحذف | Deleted", show_alert=True)439    440    await my_bots(update, context)441 442# ─── Guide ─────────────────────────────────────────────────────────────────────443async def guide(update: Update, context: ContextTypes.DEFAULT_TYPE):444    query = update.callback_query445    await query.answer()446 447    text = (448        "📖 *دليل الاستضافة الكامل | Full Hosting Guide*\n"449        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"450        "🔵 *ما هو Replit؟ | What is Replit?*\n"451        "منصة مجانية لتشغيل الكود مباشرة في المتصفح.\n"452        "Free platform to run code directly in browser.\n\n"453        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"454        "📋 *خطوات الاستضافة | Hosting Steps:*\n\n"455        "1️⃣ سجّل في [replit.com](https://replit.com)\n"456        "2️⃣ اضغط *+ Create Repl*\n"457        "3️⃣ اختر *Python* كنوع المشروع\n"458        "4️⃣ ارفع الملفات اللي أرسلها البوت\n"459        "5️⃣ اضغط ▶️ *Run*\n"460        "6️⃣ بوتك شغّال! 🎉\n\n"461        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"462        "⏰ *الإبقاء على البوت 24/7:*\n\n"463        "1️⃣ سجّل في [uptimerobot.com](https://uptimerobot.com)\n"464        "2️⃣ أضف Monitor جديد (HTTP)\n"465        "3️⃣ ضع رابط Replit بتاعك\n"466        "4️⃣ البوت هيشتغل طول الوقت! ✅\n\n"467        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"468        "❓ *مشاكل شائعة | Common Issues:*\n\n"469        "• *البوت بيوقف بعد فترة* → استخدم UptimeRobot\n"470        "• *خطأ في المكتبات* → تأكد من requirements.txt\n"471        "• *التوكن خاطئ* → راجع @BotFather"472    )473 474    await query.edit_message_text(text, reply_markup=back_btn(), parse_mode=ParseMode.MARKDOWN,475                                  disable_web_page_preview=True)476 477# ─── About ─────────────────────────────────────────────────────────────────────478async def about(update: Update, context: ContextTypes.DEFAULT_TYPE):479    query = update.callback_query480    await query.answer()481 482    db = load_db()483    total = db["stats"].get("total_hosted", 0)484    total_users = len(db["users"])485 486    text = (487        "ℹ️ *عن البوت | About the Bot*\n"488        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"489        "🤖 *Replit Host Bot*\n"490        "بوت لاستضافة بوتات تيليجرام مجاناً\n"491        "Free Telegram bot hosting assistant\n\n"492        f"📊 *إحصائيات | Statistics:*\n"493        f"• 👥 المستخدمون | Users: `{total_users}`\n"494        f"• 🚀 بوتات تمت استضافتها | Bots hosted: `{total}`\n\n"495        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"496        "⚙️ *التقنيات المستخدمة | Tech Stack:*\n"497        "• Python 3.11\n"498        "• python-telegram-bot 21.6\n"499        "• Replit Free Tier\n\n"500        "💚 *مجاني تماماً | 100% Free*"501    )502    await query.edit_message_text(text, reply_markup=back_btn(), parse_mode=ParseMode.MARKDOWN)503 504# ─── Support ───────────────────────────────────────────────────────────────────505async def support(update: Update, context: ContextTypes.DEFAULT_TYPE):506    query = update.callback_query507    await query.answer()508 509    text = (510        "📞 *الدعم الفني | Support*\n"511        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"512        "🇸🇦 هل واجهت مشكلة؟ أرسل وصف المشكلة للأدمن:\n"513        "🇬🇧 Facing an issue? Send your problem to admin:\n\n"514        "👤 *Admin:* @YourUsername\n\n"515        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"516        "📌 *قبل التواصل، تأكد من:*\n"517        "• قراءة الدليل /guide\n"518        "• تحميل جميع الملفات\n"519        "• التوكن صحيح"520    )521    await query.edit_message_text(text, reply_markup=back_btn(), parse_mode=ParseMode.MARKDOWN)522 523# ─── Admin Panel ───────────────────────────────────────────────────────────────524async def admin(update: Update, context: ContextTypes.DEFAULT_TYPE):525    if update.effective_user.id != ADMIN_ID:526        await update.message.reply_text("🚫 غير مصرح | Not authorized")527        return528 529    db = load_db()530    total_users = len(db["users"])531    total_bots = len(db["bots"])532    banned = sum(1 for u in db["users"].values() if u.get("banned"))533 534    text = (535        "🔧 *لوحة الأدمن | Admin Panel*\n"536        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"537        f"👥 المستخدمون: `{total_users}`\n"538        f"🤖 البوتات: `{total_bots}`\n"539        f"🚫 المحظورون: `{banned}`\n"540        f"🚀 إجمالي الاستضافات: `{db['stats'].get('total_hosted', 0)}`\n\n"541    )542 543    keyboard = InlineKeyboardMarkup([544        [InlineKeyboardButton("👥 المستخدمون | Users", callback_data="admin_users")],545        [InlineKeyboardButton("📢 بث رسالة | Broadcast", callback_data="admin_broadcast")],546        [InlineKeyboardButton("🤖 كل البوتات | All Bots", callback_data="admin_all_bots")],547    ])548    await update.message.reply_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)549 550async def admin_users(update: Update, context: ContextTypes.DEFAULT_TYPE):551    query = update.callback_query552    await query.answer()553    if update.effective_user.id != ADMIN_ID:554        return555 556    db = load_db()557    text = "👥 *قائمة المستخدمين | Users List*\n\n"558 559    for uid, udata in list(db["users"].items())[:20]:560        status = "🚫" if udata.get("banned") else "✅"561        name = udata.get("full_name", "Unknown")562        bots_count = len(udata.get("bots", []))563        text += f"{status} `{uid}` — {name} — 🤖 {bots_count}\n"564 565    keyboard = InlineKeyboardMarkup([566        [InlineKeyboardButton("🚫 حظر مستخدم | Ban User", callback_data="admin_ban")],567        [InlineKeyboardButton("✅ رفع حظر | Unban User", callback_data="admin_unban")],568        [InlineKeyboardButton("🔙 رجوع", callback_data="admin_back")]569    ])570    await query.edit_message_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)571 572async def admin_all_bots(update: Update, context: ContextTypes.DEFAULT_TYPE):573    query = update.callback_query574    await query.answer()575    if update.effective_user.id != ADMIN_ID:576        return577 578    db = load_db()579    text = "🤖 *كل البوتات | All Bots*\n\n"580 581    for bid, bdata in list(db["bots"].items())[:15]:582        text += f"• *{bdata['name']}* — 👤 `{bdata['owner_id']}` — 📅 {bdata['created'][:10]}\n"583 584    if not db["bots"]:585        text += "لا يوجد بوتات مسجّلة بعد."586 587    await query.edit_message_text(text, reply_markup=back_btn("admin_back"), parse_mode=ParseMode.MARKDOWN)588 589async def admin_ban_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):590    if update.effective_user.id != ADMIN_ID:591        return592    args = context.args593    if not args:594        await update.message.reply_text("الاستخدام: /ban [user_id]")595        return596    uid = args[0]597    db = load_db()598    if uid in db["users"]:599        db["users"][uid]["banned"] = True600        save_db(db)601        await update.message.reply_text(f"✅ تم حظر المستخدم `{uid}`", parse_mode=ParseMode.MARKDOWN)602    else:603        await update.message.reply_text("❌ المستخدم غير موجود")604 605async def admin_unban_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):606    if update.effective_user.id != ADMIN_ID:607        return608    args = context.args609    if not args:610        await update.message.reply_text("الاستخدام: /unban [user_id]")611        return612    uid = args[0]613    db = load_db()614    if uid in db["users"]:615        db["users"][uid]["banned"] = False616        save_db(db)617        await update.message.reply_text(f"✅ تم رفع الحظر عن `{uid}`", parse_mode=ParseMode.MARKDOWN)618    else:619        await update.message.reply_text("❌ المستخدم غير موجود")620 621async def admin_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):622    if update.effective_user.id != ADMIN_ID:623        return624    db = load_db()625    text = (626        "📊 *إحصائيات | Statistics*\n\n"627        f"👥 المستخدمون: `{len(db['users'])}`\n"628        f"🤖 البوتات المسجّلة: `{len(db['bots'])}`\n"629        f"🚀 إجمالي الاستضافات: `{db['stats'].get('total_hosted', 0)}`\n"630        f"🚫 المحظورون: `{sum(1 for u in db['users'].values() if u.get('banned'))}`"631    )632    await update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN)633 634# Broadcast635broadcast_waiting = {}636 637async def admin_broadcast_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):638    query = update.callback_query639    await query.answer()640    if update.effective_user.id != ADMIN_ID:641        return642    await query.edit_message_text(643        "📢 *بث رسالة | Broadcast*\n\nأرسل الرسالة الآن:",644        reply_markup=back_btn("admin_back"),645        parse_mode=ParseMode.MARKDOWN646    )647    broadcast_waiting[update.effective_user.id] = True648 649async def broadcast_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):650    if update.effective_user.id != ADMIN_ID:651        return652    if not context.args:653        await update.message.reply_text("الاستخدام: /broadcast [رسالة]")654        return655    msg = " ".join(context.args)656    db = load_db()657    sent, failed = 0, 0658    for uid in db["users"]:659        try:660            await context.bot.send_message(int(uid), f"📢 *رسالة من الأدمن:*\n\n{msg}", parse_mode=ParseMode.MARKDOWN)661            sent += 1662        except:663            failed += 1664    await update.message.reply_text(f"✅ تم الإرسال: `{sent}`\n❌ فشل: `{failed}`", parse_mode=ParseMode.MARKDOWN)665 666async def admin_back_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):667    query = update.callback_query668    await query.answer()669    if update.effective_user.id != ADMIN_ID:670        return671    db = load_db()672    total_users = len(db["users"])673    total_bots = len(db["bots"])674    banned = sum(1 for u in db["users"].values() if u.get("banned"))675    text = (676        "🔧 *لوحة الأدمن | Admin Panel*\n"677        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"678        f"👥 المستخدمون: `{total_users}`\n"679        f"🤖 البوتات: `{total_bots}`\n"680        f"🚫 المحظورون: `{banned}`\n"681    )682    keyboard = InlineKeyboardMarkup([683        [InlineKeyboardButton("👥 المستخدمون | Users", callback_data="admin_users")],684        [InlineKeyboardButton("📢 بث رسالة | Broadcast", callback_data="admin_broadcast")],685        [InlineKeyboardButton("🤖 كل البوتات | All Bots", callback_data="admin_all_bots")],686    ])687    await query.edit_message_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)688 689# ─── /help ─────────────────────────────────────────────────────────────────────690async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):691    text = (692        "❓ *المساعدة | Help*\n"693        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"694        "🇸🇦 *الأوامر المتاحة:*\n"695        "/start — القائمة الرئيسية\n"696        "/host — استضف بوت جديد\n"697        "/mybots — بوتاتي المسجّلة\n"698        "/guide — دليل الاستضافة\n"699        "/support — الدعم الفني\n"700        "/help — هذه الرسالة\n\n"701        "🇬🇧 *Available Commands:*\n"702        "/start — Main menu\n"703        "/host — Host a new bot\n"704        "/mybots — My registered bots\n"705        "/guide — Hosting guide\n"706        "/support — Technical support\n"707        "/help — This message"708    )709    await update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN)710 711async def host_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):712    """Direct /host command"""713    user = update.effective_user714    if is_banned(user.id):715        await update.message.reply_text("🚫 تم حظرك.\n🚫 You are banned.")716        return717 718    register_user(user.id, user.username or "", user.full_name or "")719    text = (720        "🚀 *استضافة بوت جديد | Host a New Bot*\n\n"721        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"722        "🇸🇦 *الخطوة 1/3:* أرسل توكن البوت\n"723        "احصل عليه من @BotFather\n\n"724        "🇬🇧 *Step 1/3:* Send your bot token\n"725        "Get it from @BotFather\n\n"726        "📌 *مثال | Example:*\n"727        "`1234567890:ABCdefGHIjklMNOpqrSTUvwxYZ`"728    )729    await update.message.reply_text(text, reply_markup=back_btn("main_menu"), parse_mode=ParseMode.MARKDOWN)730    return WAITING_TOKEN731 732async def mybots_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):733    user = update.effective_user734    if is_banned(user.id):735        return736 737    db = load_db()738    uid = str(user.id)739    user_bots = db["users"].get(uid, {}).get("bots", [])740 741    if not user_bots:742        await update.message.reply_text(743            "📋 لا يوجد بوتات مسجّلة بعد.\n📋 No bots registered yet.",744            reply_markup=InlineKeyboardMarkup([[745                InlineKeyboardButton("🚀 استضف بوت | Host a Bot", callback_data="host_bot")746            ]])747        )748        return749 750    text = "📋 *بوتاتي | My Bots*\n\n"751    for bot_id in user_bots:752        bot = db["bots"].get(bot_id)753        if bot:754            text += f"🤖 *{bot['name']}* — 📅 {bot['created'][:10]}\n"755 756    await update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN)757 758# ─── Main ──────────────────────────────────────────────────────────────────────759def main():760    app = Application.builder().token(BOT_TOKEN).build()761 762    # Conversation handler for hosting flow763    conv_handler = ConversationHandler(764        entry_points=[765            CallbackQueryHandler(host_bot_start, pattern="^host_bot$"),766            CommandHandler("host", host_cmd),767        ],768        states={769            WAITING_TOKEN: [MessageHandler(filters.TEXT & ~filters.COMMAND, receive_token)],770            WAITING_BOT_NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, receive_bot_name)],771            WAITING_CODE: [772                MessageHandler(filters.TEXT & ~filters.COMMAND, receive_code),773                MessageHandler(filters.Document.ALL, receive_code),774            ],775        },776        fallbacks=[777            CallbackQueryHandler(cancel_host, pattern="^main_menu$"),778            CommandHandler("cancel", cancel_host),779        ],780        allow_reentry=True,781    )782 783    # Handlers784    app.add_handler(CommandHandler("start", start))785    app.add_handler(CommandHandler("help", help_cmd))786    app.add_handler(CommandHandler("mybots", mybots_cmd))787    app.add_handler(CommandHandler("admin", admin))788    app.add_handler(CommandHandler("ban", admin_ban_cmd))789    app.add_handler(CommandHandler("unban", admin_unban_cmd))790    app.add_handler(CommandHandler("stats", admin_stats))791    app.add_handler(CommandHandler("broadcast", broadcast_cmd))792    app.add_handler(conv_handler)793 794    # Callbacks795    app.add_handler(CallbackQueryHandler(main_menu_callback, pattern="^main_menu$"))796    app.add_handler(CallbackQueryHandler(my_bots, pattern="^my_bots$"))797    app.add_handler(CallbackQueryHandler(guide, pattern="^guide$"))798    app.add_handler(CallbackQueryHandler(about, pattern="^about$"))799    app.add_handler(CallbackQueryHandler(support, pattern="^support$"))800    app.add_handler(CallbackQueryHandler(delete_bot_callback, pattern="^del_"))801    app.add_handler(CallbackQueryHandler(admin_users, pattern="^admin_users$"))802    app.add_handler(CallbackQueryHandler(admin_all_bots, pattern="^admin_all_bots$"))803    app.add_handler(CallbackQueryHandler(admin_broadcast_callback, pattern="^admin_broadcast$"))804    app.add_handler(CallbackQueryHandler(admin_back_callback, pattern="^admin_back$"))805 806    print("🚀 Bot is running...")807    app.run_polling(drop_pending_updates=True)808 809if __name__ == "__main__":810    main()811