Download app.py from Vvbbnnn/Ch: direct link, hf CLI and curl.
- Browser
- Download file 16.3 kB
-
https://huggingface.co/spaces/Vvbbnnn/Ch/resolve/main/app.py
- Command line
-
hf download hf://spaces/Vvbbnnn/Ch/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Vvbbnnn/Ch/resolve/main/app.py
16.3 kB
| import os | |
| import sys | |
| import logging | |
| import nest_asyncio | |
| import random | |
| import asyncio | |
| import pytz | |
| from flask import Flask | |
| from threading import Thread | |
| from datetime import datetime, timedelta | |
| from pymongo import MongoClient | |
| from apscheduler.schedulers.asyncio import AsyncIOScheduler | |
| from apscheduler.triggers.cron import CronTrigger | |
| from telethon import TelegramClient, events, Button | |
| from telethon.sessions import StringSession | |
| from telethon.tl import functions | |
| import re | |
| from telethon.tl.custom import Conversation | |
| from telethon import TelegramClient, events | |
| from telethon.sessions import StringSession | |
| from session_converter import SessionManager | |
| # βββββ Utils βββββ | |
| adjectives = ["Silent", "Crazy", "Golden", "Hidden", "Brave", "Fierce", "Mysterious", "Savage", "Royal", "Witty", "Legendary", "Epic", "Noble", "Clever", "Loyal", "Wild", "Electric", "Fearless", "Crimson", "Frozen", "Charming", "Rebel", "Turbo", "Lone", "Radiant", "Raging", "Dusty", "Majestic", "Grumpy", "Shadow"] | |
| nouns = ["Warriors", "Coders", "Friends", "Legends", "Pirates", "Tigers", "Wolves", "Hackers", "Ninjas", "Riders", "Hunters", "Kings", "Queens", "Giants", "Lords", "Champions", "Stormers", "Creators", "Ghosts", "Wizards", "Knights", "Samurais", "Explorers", "Titans", "Outlaws", "Rebels", "Squad", "Troopers", "Dreamers", "Avengers"] | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(message)s", stream=sys.stdout) | |
| log = logging.getLogger("app") | |
| nest_asyncio.apply() | |
| API_ID = int(os.getenv("API_ID", 3704772)) | |
| API_HASH = os.getenv("API_HASH", "b8e50a035abb851c0dd424e14cac4c06") | |
| BOT_TOKEN = os.getenv("BOT_TOKEN") | |
| MONGO_URI = os.getenv("MONGO_URI") | |
| ADMIN_ID = int(os.getenv("ADMIN_ID", 6574063018)) | |
| client = MongoClient(MONGO_URI) | |
| db = client["telethon_bots"] | |
| accounts = db["accounts"] | |
| plans = db["plans"] | |
| bot = TelegramClient("bot", API_ID, API_HASH) | |
| userbots = {} | |
| scheduler = AsyncIOScheduler() | |
| def random_group_name(): | |
| return f"{random.choice(adjectives)} {random.choice(nouns)}" | |
| # Timezone | |
| tz = pytz.timezone("Asia/Kolkata") | |
| # Dummy userbot registry | |
| userbots = {} # Fill this with: {user_id: bot_instance} | |
| def create_plan(account, limit): | |
| now = datetime.now(tz) | |
| end_of_day = now.replace(hour=23, minute=59, second=59, microsecond=0) | |
| time_gap = (end_of_day - now) / limit | |
| times = [] | |
| for i in range(limit): | |
| planned_time = now + i * time_gap | |
| # Ensure it's a future time (at least 1 minute ahead) | |
| if planned_time <= now: | |
| planned_time = now + timedelta(minutes=1) | |
| times.append(planned_time) | |
| for t in times: | |
| plans.insert_one({ | |
| "account_id": account["_id"], | |
| "scheduled_time": t.isoformat() | |
| }) | |
| print(f"β Created {len(times)} plan(s) for account {account['_id']}") | |
| def apply_plan(): | |
| now = datetime.now(tz) | |
| count = 0 | |
| for plan in plans.find(): | |
| plan_time = datetime.fromisoformat(plan["scheduled_time"]).astimezone(tz) | |
| if plan_time > now: | |
| account = accounts.find_one({"_id": plan["account_id"]}) | |
| if not account: | |
| continue | |
| userbot = userbots.get(account["_id"]) | |
| if not userbot: | |
| print(f"β οΈ No userbot for account {account['_id']}, skipping...") | |
| continue | |
| def job_wrapper(acc_id): | |
| def job(): | |
| print(f"π Running job for account {acc_id} at {datetime.now(tz)}") | |
| # Put your real logic here | |
| return job | |
| job_id = f"job_{plan['_id']}" | |
| scheduler.add_job(job_wrapper(account["_id"]), trigger='date', run_date=plan_time, id=job_id) | |
| print(f"π Scheduled job for account {account['_id']} at {plan_time.strftime('%H:%M:%S')} (ID: {job_id})") | |
| count += 1 | |
| print(f"β Applied and scheduled {count} job(s).") | |
| def reset_and_plan(): | |
| print("π Resetting plans and scheduling new ones...") | |
| plans.delete_many({}) | |
| for acc in accounts.find(): | |
| limit = random.randint(3, 5) | |
| create_plan(acc, limit) | |
| apply_plan() | |
| print("β Plans created and scheduled.") | |
| # Schedule reset daily at 00:00 IST | |
| scheduler.add_job(reset_and_plan, CronTrigger(hour=0, minute=0, timezone="Asia/Kolkata"), id="daily_reset_job", replace_existing=True) | |
| # Telethon /reset command | |
| async def handle_reset(event): | |
| sender = await event.get_sender() | |
| if sender.id != ADMIN_ID: | |
| return await event.reply("β You are not authorized to run this command.") | |
| for job in scheduler.get_jobs(): | |
| if job.func.__name__ == "reset_and_plan" or job.id == "daily_reset_job": | |
| job.remove() | |
| reset_and_plan() | |
| scheduler.add_job(reset_and_plan, CronTrigger(hour=0, minute=0, timezone="Asia/Kolkata"), id="daily_reset_job", replace_existing=True) | |
| await event.reply("β Schedule reset and re-planned for tonight 00:00 IST.") | |
| async def handle_stats(event): | |
| tz = pytz.timezone("Asia/Kolkata") | |
| now = datetime.now(tz) | |
| msg = "π **Today's Schedule:**\n\n" | |
| msg += f"ποΈ Date: {now.strftime('%d/%m/%Y')}\n" | |
| msg += f"π Time: {now.strftime('%I:%M %p')} IST\n\n" | |
| plans_today = list(plans.find()) | |
| if not plans_today: | |
| return await event.reply("π No plans found today.") | |
| for plan in plans_today: | |
| acc = accounts.find_one({"user_id": plan["user_id"]}) | |
| if not acc: | |
| continue | |
| name = acc["name"] | |
| times_str = ", ".join([t.astimezone(tz).strftime("%I:%M %p") for t in plan["times"]]) | |
| created = plan.get("created", 0) | |
| msg += f"π€ **{name}** β `{times_str}`\nβ Created: `{created}`\n\n" | |
| next_run = None | |
| for job in scheduler.get_jobs(): | |
| if job.id == "daily_reset_job": | |
| next_run = job.next_run_time | |
| break | |
| if next_run: | |
| msg += f"π Next Reset: `{next_run.astimezone(tz).strftime('%d/%m/%Y %I:%M %p')} IST`" | |
| await event.reply(msg) | |
| async def auto_create_groups(userbot, acc_doc, plan_doc=None): | |
| if plan_doc and plan_doc["created"] >= len(plan_doc["times"]): | |
| await bot.send_message(ADMIN_ID, f"β Group creation skipped: Limit exceeded for {acc_doc['name']}") | |
| return | |
| try: | |
| title = random_group_name() | |
| result = await userbot(functions.channels.CreateChannelRequest(title=title, about=",", megagroup=True)) | |
| group = result.chats[0].id | |
| for _ in range(4): | |
| await userbot.send_message(group, random_group_name()) | |
| await asyncio.sleep(2) | |
| try: | |
| stickers = ["CAACAgUAAxkBAAEKZStlTxkC-cvQJwABvHoUjRacAVIHCFcAAgECAALaTqVVCpx_Lc2ZoLguBA"] | |
| await userbot.send_file(group, random.choice(stickers)) | |
| except: | |
| pass | |
| if plan_doc: | |
| plans.update_one({"user_id": acc_doc["user_id"]}, {"$inc": {"created": 1}}) | |
| info = await userbot.get_me() | |
| await bot.send_message(ADMIN_ID, f"β Created 1 group\nπ€ {info.first_name}\nπ @{info.username or 'N/A'}\nπ Created today: {plan_doc['created'] + 1 if plan_doc else 'Manual'}") | |
| except Exception as e: | |
| await bot.send_message(ADMIN_ID, f"β Group creation failed for {acc_doc['name']}: {e}") | |
| log.error(f"β Group creation failed: {e}") | |
| async def start_userbot(session_str, owner_id): | |
| try: | |
| userbot = TelegramClient(StringSession(session_str), API_ID, API_HASH) | |
| await userbot.start() | |
| info = await userbot.get_me() | |
| if accounts.find_one({"user_id": info.id}): | |
| return None | |
| doc = { | |
| "user_id": info.id, | |
| "name": info.first_name, | |
| "username": info.username or None, | |
| "session": session_str, | |
| "created": 0, | |
| "owner_id": owner_id, | |
| "added_on": datetime.utcnow() | |
| } | |
| accounts.insert_one(doc) | |
| userbots[info.id] = userbot | |
| asyncio.create_task(userbot.run_until_disconnected()) | |
| return info | |
| except Exception as e: | |
| log.info(f"β Failed to add account: {e}") | |
| return None | |
| async def load_all_userbots(): | |
| log.info("π Loading all stored userbots...") | |
| for acc in accounts.find(): | |
| try: | |
| ub = TelegramClient(StringSession(acc["session"]), API_ID, API_HASH) | |
| await ub.start() | |
| userbots[acc["user_id"]] = ub | |
| asyncio.create_task(ub.run_until_disconnected()) | |
| log.info(f"β Loaded: {acc['name']} (@{acc.get('username', 'N/A')})") | |
| except Exception as e: | |
| await bot.send_message(ADMIN_ID, f"β Failed to start {acc['name']}") | |
| log.info(f"β Failed to start {acc['name']}: {e}") | |
| # βββββ Bot Commands βββββ | |
| async def start_cmd(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| await event.reply( | |
| "π Welcome!\n\n" | |
| "/addacc β Add account\n" | |
| "/delacc β Delete an account\n" | |
| "/total β Count of connected accounts\n" | |
| "/stats β View today's schedule\n" | |
| "/reset β Reset and re-plan daily schedule\n" | |
| "/create <account_name> β Create groups for the specified account\n" | |
| "/help β Show this help message" | |
| ) | |
| async def help_cmd(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| await event.reply( | |
| "π οΈ **Bot Commands Help:**\n\n" | |
| "/start β Start the bot and see the available commands\n" | |
| "/addacc β Add a new account to the bot\n" | |
| "/delacc β Delete an existing account\n" | |
| "/total β Get the total count of connected accounts\n" | |
| "/stats β View today's scheduling plan for accounts\n" | |
| "/reset β Reset and plan the schedule for the new day\n" | |
| "/create <account_name> β Create groups for the specified account\n" | |
| "/help β Show this help message\n\n" | |
| "These commands are available to the admin only." | |
| ) | |
| async def addacc_cmd(event): | |
| async with control_bot.conversation(event.chat_id, timeout=300) as conv: | |
| await conv.send_message("π© Send your StringSession:") | |
| msg = await conv.get_response() | |
| session_str = msg.raw_text.strip() | |
| # Step 1: Detect and convert Pyrogram β Telethon | |
| try: | |
| if not session_str.startswith(("1A", "1B")): # Likely Pyrogram | |
| try: | |
| session_manager = SessionManager.from_pyrogram_string_session(session_str) | |
| session_str = session_manager.telethon_string_session() | |
| await conv.send_message("π Converted Pyrogram session to Telethon.") | |
| except Exception as e: | |
| await conv.send_message(f"β Pyrogram conversion failed:\n`{e}`") | |
| return | |
| else: | |
| await conv.send_message("β Detected Telethon session.") | |
| except Exception as e: | |
| await conv.send_message(f"β Session detection failed:\n`{e}`") | |
| return | |
| info = await start_userbot(session_str, event.sender_id) | |
| if info: | |
| await conv.send_message(f"β Added: {info.first_name} (@{info.username or 'N/A'})") | |
| else: | |
| await conv.send_message("β οΈ Already added or failed.") | |
| async def total_accounts_cmd(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| count = accounts.count_documents({}) | |
| await event.respond(f"π Total connected: **{count}**") | |
| async def delacc_cmd(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| user_accs = list(accounts.find({"owner_id": ADMIN_ID})) | |
| if not user_accs: | |
| await event.reply("πΆ No accounts.") | |
| return | |
| buttons, row = [], [] | |
| for idx, acc in enumerate(user_accs, 1): | |
| row.append(Button.inline(f"{acc['name']} (@{acc.get('username', 'N/A')})", data=f"del_{acc['user_id']}")) | |
| if idx % 2 == 0: | |
| buttons.append(row) | |
| row = [] | |
| if row: | |
| buttons.append(row) | |
| await event.respond("Select to delete:", buttons=buttons) | |
| async def handle_delete(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| user_id = int(event.data.decode().split("_")[1]) | |
| acc_doc = accounts.find_one({"user_id": user_id}) | |
| if not acc_doc: | |
| await event.answer("Not found.", alert=True) | |
| return | |
| await event.edit(f"β οΈ Confirm delete {acc_doc['name']}?", buttons=[ | |
| [Button.inline("β Confirm", data=f"confdel_{user_id}"), Button.inline("β Cancel", data=b"cancel")] | |
| ]) | |
| async def confirm_delete(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| user_id = int(event.data.decode().split("_")[1]) | |
| acc_doc = accounts.find_one_and_delete({"user_id": user_id}) | |
| if acc_doc: | |
| try: | |
| if user_id in userbots: | |
| await userbots[user_id].disconnect() | |
| del userbots[user_id] | |
| await event.edit(f"β Deleted: {acc_doc['name']}") | |
| await bot.send_message(ADMIN_ID, f"ποΈ Deleted: {acc_doc['name']} (@{acc_doc.get('username', 'N/A')})") | |
| log.info(f"ποΈ Deleted account: {acc_doc['name']} (@{acc_doc.get('username', 'N/A')})") | |
| except Exception as e: | |
| await event.edit(f"Deleted from DB, error stopping: {e}") | |
| else: | |
| await event.edit("β οΈ Not found.") | |
| async def cancel_cb(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| await event.edit("β Cancelled.") | |
| async def pick_create_callback(event): | |
| if event.sender_id != ADMIN_ID: | |
| return | |
| user_id = int(event.data.decode().split("_")[1]) | |
| acc_doc = accounts.find_one({"user_id": user_id}) | |
| if not acc_doc: | |
| await event.answer("Account not found.", alert=True) | |
| return | |
| if user_id not in userbots: | |
| await event.answer("Account is not active.", alert=True) | |
| return | |
| await event.edit(f"β³ Creating groups for {acc_doc['name']}...") | |
| await auto_create_groups(userbots[user_id], acc_doc) | |
| async def create_group_cmd(event): | |
| query = event.pattern_match.group(1).strip() | |
| safe_query = re.escape(query) | |
| matches = list(accounts.find({ | |
| "$or": [ | |
| {"name": {"$regex": safe_query, "$options": "i"}}, | |
| {"username": {"$regex": safe_query, "$options": "i"}} | |
| ] | |
| })) | |
| if not matches: | |
| await event.reply("β No matching account found.") | |
| return | |
| if len(matches) == 1: | |
| acc_doc = matches[0] | |
| user_id = acc_doc["user_id"] | |
| if user_id not in userbots: | |
| await event.reply("β οΈ Account is not active.") | |
| return | |
| await event.reply(f"β³ Creating groups for {acc_doc['name']}...") | |
| await auto_create_groups(userbots[user_id], acc_doc) | |
| else: | |
| buttons = [] | |
| for acc in matches: | |
| label = f"{acc['name']} (@{acc.get('username', 'N/A')})" | |
| buttons.append([Button.inline(label, data=f"pickcreate_{acc['user_id']}")]) | |
| await event.respond("β οΈ Multiple matches found. Select the correct account:", buttons=buttons) | |
| # βββββ Flask App βββββ | |
| app = Flask(__name__) | |
| def home(): | |
| return "β Channel-making bot is running." | |
| def run_flask(): | |
| app.run(host="0.0.0.0", port=7860, use_reloader=False) | |
| # βββββ Main Startup βββββ | |
| async def main(): | |
| Thread(target=run_flask).start() | |
| scheduler.start() | |
| await load_all_userbots() | |
| await bot.start(bot_token=BOT_TOKEN) | |
| log.info("π€ Bot is now running on Hugging Face") | |
| await bot.run_until_disconnected() | |
| if __name__ == "__main__": | |
| asyncio.run(main()) | |