├── runtime.txt ├── Procfile ├── TechifyBots ├── TechifyBots.txt ├── callback.py ├── db.py ├── fsub.py └── commands.py ├── run cmd.txt ├── requirements.txt ├── app.py ├── LICENSE ├── Script.py ├── config.py ├── README.md └── bot.py /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.13.5 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 bot.py -------------------------------------------------------------------------------- /TechifyBots/TechifyBots.txt: -------------------------------------------------------------------------------- 1 | # ©TechifyBots 2 | -------------------------------------------------------------------------------- /run cmd.txt: -------------------------------------------------------------------------------- 1 | gunicorn app:app & python3 bot.py 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrofork>=2.3.68 2 | tgcrypto 3 | motor 4 | aiohttp 5 | pytz 6 | 7 | # For Web Deployable 8 | Flask 9 | gunicorn 10 | Jinja2 11 | werkzeug 12 | itsdangerous 13 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route('/') 5 | def hello_world(): 6 | return 'TechifyBots' 7 | 8 | 9 | if __name__ == "__main__": 10 | app.run() 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 TechifyBots 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Script.py: -------------------------------------------------------------------------------- 1 | class text(object): 2 | START = """{}, 3 | 4 | ɪ ᴀᴍ sɪᴍᴘʟᴇ ʙᴜᴛ ᴘᴏᴡᴇʀꜰᴜʟʟ ᴀᴜᴛᴏ ʀᴇᴀᴄᴛɪᴏɴ ʙᴏᴛ. 5 | 6 | ᴊᴜsᴛ ᴀᴅᴅ ᴍᴇ ᴀs ᴀ ᴀᴅᴍɪɴ ɪɴ ʏᴏᴜʀ ᴄʜᴀɴɴᴇʟ ᴏʀ ɢʀᴏᴜᴘ ᴛʜᴇɴ sᴇᴇ ᴍʏ ᴘᴏᴡᴇʀ 7 | 8 |
‣ ᴍᴀɪɴᴛᴀɪɴᴇᴅ ʙʏ : ʀᴀʜᴜʟ
""" 9 | 10 | LOG = """👁️‍🗨️ 𝘜𝘚𝘌𝘙 𝘋𝘌𝘛𝘈𝘐𝘓𝘚 11 | 12 | ○ 𝘐𝘋 : {} 13 | ○ 𝘋𝘊 : {} 14 | ○ 𝘍𝘪𝘳𝘴𝘵 𝘕𝘢𝘮𝘦 : {} 15 | ○ 𝘜𝘴𝘦𝘳𝘕𝘢𝘮𝘦 : {} 16 | 17 | 𝘉𝘺 = @{}""" 18 | 19 | ABOUT = """‣ ᴍʏ ɴᴀᴍᴇ : ǫᴜɪᴄᴋ ʀᴇᴀᴄᴛ ʙᴏᴛ 20 | ‣ ʟɪʙʀᴀʀʏ : ᴘʏʀᴏɢʀᴀᴍ 21 | ‣ ᴅᴀᴛᴀʙᴀsᴇ : ᴍᴏɴɢᴏᴅʙ 22 | ‣ ʟᴀɴɢᴜᴀɢᴇ : ᴘʏᴛʜᴏɴ 𝟹 23 | ‣ ʙᴏᴛ sᴇʀᴠᴇʀ : ᴋᴏʏᴇʙ 24 | ‣ ᴄʀᴇᴀᴛᴇᴅ ʙʏ : ʀᴀʜᴜʟ""" 25 | 26 | HELP = """{}, 27 | 28 | ᴛʜɪꜱ ɪꜱ ʀᴇᴀʟʟʏ sɪᴍᴘʟᴇ 😂 29 | 30 | ᴊᴜsᴛ ᴍᴀᴋᴇ ᴍᴇ ᴀᴅᴍɪɴ ɪɴ ʏᴏᴜʀ ɢʀᴏᴜᴘ ᴏʀ ᴄʜᴀɴɴᴇʟ, ᴀɴᴅ ᴇɴᴊᴏʏ ᴀᴜᴛᴏᴍᴀᴛᴇᴅ ᴍᴀɢɪᴄᴀʟ ʀᴇᴀᴄᴛɪᴏɴs 💞 31 | 32 |
𝖲𝗍𝗂𝗅𝗅 𝗁𝖺𝗏𝖾 𝗂𝗌𝗌𝗎𝖾𝗌? 𝖴𝗌𝖾 /help
""" -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import List 3 | 4 | API_ID = os.environ.get("API_ID", "") 5 | API_HASH = os.environ.get("API_HASH", "") 6 | BOT_TOKEN = os.environ.get("BOT_TOKEN", "") 7 | ADMIN = int(os.environ.get("ADMIN", "1255023013")) 8 | PICS = (os.environ.get("PICS", "https://i.ibb.co/7NX2TY1N/photo-2025-07-13-12-32-15-7531449578462117904.jpg https://i.ibb.co/3mSrtgDw/photo-2025-07-14-08-03-12-7526845489484922908.jpg https://i.ibb.co/8nNgvwyn/photo-2025-07-14-08-02-56-7526846752205307932.jpg https://i.ibb.co/bgH9CXnx/photo-2024-11-07-03-36-42-7531449810390351892.jpg https://i.ibb.co/s9gt09Vq/photo-2025-07-14-08-00-51-7531450025138716692.jpg https://i.ibb.co/8g1fH31T/cutie.jpg")).split() 9 | 10 | LOG_CHANNEL = int(os.environ.get("LOG_CHANNEL", "-1002686843200")) 11 | 12 | DB_URI = os.environ.get("DB_URI", "") 13 | DB_NAME = os.environ.get("DB_NAME", "store") 14 | 15 | IS_FSUB = os.environ.get("IS_FSUB", "False").lower() == "true" # Set "True" For Enable Force Subscribe 16 | AUTH_CHANNELS = list(map(int, os.environ.get("AUTH_CHANNEL", "").split())) # Add Multiple channel ids 17 | AUTH_REQ_CHANNELS = list(map(int, os.environ.get("AUTH_REQ_CHANNEL", "").split())) # Add Multiple channel ids 18 | FSUB_EXPIRE = int(os.environ.get("FSUB_EXPIRE", 2)) # minutes, 0 = no expiry 19 | 20 | EMOJIS = [ 21 | "👍", "❤️", "🔥", "🥰", "👏", "😁", "🤔", "🤯", "😱", "😢", 22 | "🎉", "🤩", "🙏", "👌", "🕊", "🤡", "🥱", "🥴", "😍", "🤷‍♂️", 23 | "❤️‍🔥", "🌚", "💯", "🤣", "⚡", "🏆", "🗿", "😐", "🤨", "🍾", 24 | "💋", "😈", "😴", "😭", "🤓", "👻", "👨‍💻", "👀", "🙈", "🤷‍♀️", 25 | "😇", "🤝", "✍️", "🤗", "🫡", "😨", "🧑‍🎄", "🎄", "⛄", "🤪", 26 | "🆒", "💘", "🙊", "🦄", "😘", "🙉", "💊", "😎", "👾", "🤷" 27 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Auto Reaction Bot 3 |

4 | 5 |

🩷 Thanks for Being Here 🩷

6 | 7 | 8 | 9 | ### 🥰 FEATURES 10 | 11 |
Tap On Me For Bot Features 12 | 13 | - unlimited reactions 14 | - Supports all type of emojies 15 | - work in both channels & groups 16 | - Fully modified repo 17 | - Stats & Broadcast feature available 18 | - Fsub & Log channel support 19 | - Deploy To Koyeb + Heroku + Railway. 20 | - [Developer support](https://telegram.me/TechifySupport) 24x7 21 |
22 | 23 | 24 | ### 🔥 VARIABLES 25 | 26 |
Tap On Me For Environment Variable 27 | 28 | - `API_ID` : Get From [Here](https://youtu.be/y5FwAobQ-Kc) 29 | - `API_HASH` : Get From [Here](https://youtu.be/y5FwAobQ-Kc) 30 | - `BOT_TOKEN` : Get From [BotFather](https://youtu.be/aJILCCXfNVM) 31 | - `PICS` - Your bot start images (you can add multiple images) 32 | - `ADMIN` : Your Telegram User ID 33 | - `DB_URI` : MongoDB database get from [here](https://youtu.be/j8LIuM7vv18) 34 | - `LOG_CHANNEL` : Your Log channel ID. 35 | - `FSUB_EXPIRE` : Your FSUB link expire time. 36 | - `AUTH_CHANNELS` : Your Public & Private FSUB channels ID. 37 | - `AUTH_REQ_CHANNELS` : Your Private Request FSUB channels ID. 38 |
39 | 40 | ### 😍 COMMANDS 41 | 42 |
Tap On Me For Commands 43 | 44 | ``` 45 | start - Start The Bot 46 | broadcast - (admin only) Broadcast message to bot users 47 | stats - (admin only) check bots stats 48 | ``` 49 |
50 | 51 | ### 💞 CREDIT 52 | - [TechifyBots](https://github.com/TechifyBots) 53 | 54 | ### 😇 [SUPPORT](https://techifybots.github.io/PayWeb) 55 | 56 | ### 🥳 [DEVELOPER](https://instagram.com/ImRahulDhankhar) 57 | 58 | ### 📌 NOTE 59 | 60 | 𝘊𝘰𝘱𝘺𝘪𝘯𝘨 𝘰𝘳 𝘚𝘦𝘭𝘭𝘪𝘯𝘨 𝘵𝘩𝘪𝘴 𝘳𝘦𝘱𝘰 𝘪𝘴 𝘴𝘵𝘳𝘪𝘤𝘵𝘭𝘺 𝘱𝘳𝘰𝘩𝘪𝘣𝘪𝘵𝘦𝘥.
-------------------------------------------------------------------------------- /TechifyBots/callback.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client 2 | from pyrogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup 3 | from Script import text 4 | from config import ADMIN 5 | 6 | @Client.on_callback_query() 7 | async def callback_query_handler(client, query: CallbackQuery): 8 | if query.data == "start": 9 | await query.message.edit_caption( 10 | caption=text.START.format(query.from_user.mention), 11 | reply_markup=InlineKeyboardMarkup([ 12 | [InlineKeyboardButton('⇆ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖢𝗁𝖺𝗇𝗇𝖾𝗅 ⇆', url='https://telegram.me/QuickReactRobot?startgroup=botstart')], 13 | [InlineKeyboardButton('ℹ️ 𝖠𝖻𝗈𝗎𝗍', callback_data='about'), 14 | InlineKeyboardButton('📚 𝖧𝖾𝗅𝗉', callback_data='help')], 15 | [InlineKeyboardButton('⇆ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖢𝗁𝖺𝗇𝗇𝖾𝗅 ⇆', url='https://telegram.me/QuickReactRobot?startchannel=botstart')] 16 | ]) 17 | ) 18 | 19 | elif query.data == "help": 20 | await query.message.edit_caption( 21 | caption=text.HELP.format(query.from_user.mention), 22 | reply_markup=InlineKeyboardMarkup([ 23 | [InlineKeyboardButton('📢 𝖴𝗉𝖽𝖺𝗍𝖾𝗌', url='https://telegram.me/Techifybots'), 24 | InlineKeyboardButton('💬 𝖲𝗎𝗉𝗉𝗈𝗋𝗍', url='https://telegram.me/TechifySupport')], 25 | [InlineKeyboardButton('↩️ 𝖡𝖺𝖼𝗄', callback_data="start"), 26 | InlineKeyboardButton('❌ 𝖢𝗅𝗈𝗌𝖾', callback_data="close")] 27 | ]) 28 | ) 29 | 30 | elif query.data == "about": 31 | await query.message.edit_caption( 32 | caption=text.ABOUT, 33 | reply_markup=InlineKeyboardMarkup([ 34 | [InlineKeyboardButton('👨‍💻 𝖣𝖾𝗏𝖾𝗅𝗈𝗉𝖾𝗋 👨‍💻', user_id=int(ADMIN))], 35 | [InlineKeyboardButton('↩️ 𝖡𝖺𝖼𝗄', callback_data="start"), 36 | InlineKeyboardButton('❌ 𝖢𝗅𝗈𝗌𝖾', callback_data="close")] 37 | ]) 38 | ) 39 | 40 | elif query.data == "close": 41 | await query.message.delete() 42 | 43 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import datetime 3 | from pytz import timezone 4 | from pyrogram import Client 5 | from aiohttp import web 6 | from config import API_ID, API_HASH, BOT_TOKEN, ADMIN, LOG_CHANNEL 7 | 8 | routes = web.RouteTableDef() 9 | 10 | @routes.get("/", allow_head=True) 11 | async def root_route(request): 12 | return web.Response(text="

I am Alive

", content_type='text/html') 13 | 14 | async def web_server(): 15 | app = web.Application(client_max_size=30_000_000) 16 | app.add_routes(routes) 17 | return app 18 | 19 | class Bot(Client): 20 | def __init__(self): 21 | super().__init__( 22 | "techifybots", 23 | api_id=API_ID, 24 | api_hash=API_HASH, 25 | bot_token=BOT_TOKEN, 26 | plugins=dict(root="TechifyBots"), 27 | workers=200, 28 | sleep_threshold=15 29 | ) 30 | 31 | async def start(self): 32 | app = web.AppRunner(await web_server()) 33 | await app.setup() 34 | try: 35 | await web.TCPSite(app, "0.0.0.0", int(os.getenv("PORT", 8080))).start() 36 | print("Web server started.") 37 | except Exception as e: 38 | print(f"Web server error: {e}") 39 | 40 | 41 | await super().start() 42 | me = await self.get_me() 43 | print(f"Bot Started as {me.first_name}") 44 | if isinstance(ADMIN, int): 45 | try: 46 | await self.send_message(ADMIN, f"**{me.first_name} is started...**") 47 | except Exception as e: 48 | print(f"Error sending message to admin: {e}") 49 | if LOG_CHANNEL: 50 | try: 51 | now = datetime.now(timezone("Asia/Kolkata")) 52 | msg = ( 53 | f"**{me.mention} is restarted!**\n\n" 54 | f"📅 Date : `{now.strftime('%d %B, %Y')}`\n" 55 | f"⏰ Time : `{now.strftime('%I:%M:%S %p')}`\n" 56 | f"🌐 Timezone : `Asia/Kolkata`" 57 | ) 58 | await self.send_message(LOG_CHANNEL, msg) 59 | except Exception as e: 60 | print(f"Error sending to LOG_CHANNEL: {e}") 61 | 62 | async def stop(self, *args): 63 | await super().stop() 64 | print(f"{me.first_name} Bot stopped.") 65 | 66 | Bot().run() 67 | -------------------------------------------------------------------------------- /TechifyBots/db.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | from config import DB_URI, DB_NAME 3 | from motor import motor_asyncio 4 | from pymongo import ReturnDocument 5 | from pymongo.errors import DuplicateKeyError 6 | from bson import ObjectId 7 | 8 | client = motor_asyncio.AsyncIOMotorClient(DB_URI) 9 | db = client[DB_NAME] 10 | 11 | class Techifybots: 12 | def __init__(self): 13 | self.users = db["users"] 14 | self.cache: dict[int, dict[str, Any]] = {} 15 | 16 | async def add_user(self, user_id: int, name: str) -> dict[str, Any] | None: 17 | try: 18 | user = {"user_id": int(user_id), "name": name} 19 | saved = await self.users.find_one_and_update( 20 | {"user_id": user["user_id"]}, 21 | {"$set": user}, 22 | upsert=True, 23 | return_document=ReturnDocument.AFTER 24 | ) 25 | if saved: 26 | self.cache[user["user_id"]] = saved 27 | return saved 28 | except DuplicateKeyError: 29 | existing = await self.users.find_one({"user_id": int(user_id)}) 30 | if existing: 31 | self.cache[int(user_id)] = existing 32 | return existing 33 | except Exception as e: 34 | print("Error in add_user:", e) 35 | return None 36 | 37 | async def get_user(self, user_id: int) -> dict[str, Any] | None: 38 | try: 39 | if user_id in self.cache: 40 | return self.cache[user_id] 41 | user = await self.users.find_one({"user_id": int(user_id)}) 42 | if user: 43 | self.cache[user_id] = user 44 | return user 45 | except Exception as e: 46 | print("Error in get_user:", e) 47 | return None 48 | 49 | async def get_all_users(self) -> list[dict[str, Any]]: 50 | try: 51 | users: list[dict[str, Any]] = [] 52 | async for user in self.users.find(): 53 | users.append(user) 54 | return users 55 | except Exception as e: 56 | print("Error in get_all_users:", e) 57 | return [] 58 | 59 | async def delete_user(self, identifier: int | str | ObjectId) -> bool: 60 | try: 61 | query = {} 62 | if isinstance(identifier, int): 63 | query = {"user_id": identifier} 64 | self.cache.pop(identifier, None) 65 | elif isinstance(identifier, (str, ObjectId)): 66 | query = {"_id": ObjectId(identifier)} if isinstance(identifier, str) else {"_id": identifier} 67 | doc = await self.users.find_one(query) 68 | if doc and "user_id" in doc: 69 | self.cache.pop(int(doc["user_id"]), None) 70 | else: 71 | return False 72 | result = await self.users.delete_one(query) 73 | return result.deleted_count > 0 74 | except Exception as e: 75 | print("Error in delete_user:", e) 76 | return False 77 | 78 | tb = Techifybots() -------------------------------------------------------------------------------- /TechifyBots/fsub.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import datetime 3 | from motor.motor_asyncio import AsyncIOMotorClient 4 | from pyrogram import Client, filters 5 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup, ChatJoinRequest 6 | from pyrogram.errors import UserNotParticipant, ChatAdminRequired 7 | from pyrogram.enums import ParseMode 8 | from config import AUTH_CHANNELS, AUTH_REQ_CHANNELS, ADMIN, FSUB_EXPIRE, DB_URI, DB_NAME, IS_FSUB 9 | 10 | class TechifyBots: 11 | def __init__(self): 12 | client = AsyncIOMotorClient(DB_URI) 13 | db = client[DB_NAME] 14 | self.join_requests = db["join_requests"] 15 | if FSUB_EXPIRE > 0: 16 | self.join_requests.create_index("created_at", expireAfterSeconds=FSUB_EXPIRE * 60) 17 | 18 | async def add_join_req(self, user_id: int, channel_id: int): 19 | await self.join_requests.update_one( 20 | {"user_id": user_id}, 21 | {"$addToSet": {"channels": channel_id}, "$setOnInsert": {"created_at": datetime.datetime.utcnow()}}, 22 | upsert=True 23 | ) 24 | 25 | async def has_joined_channel(self, user_id: int, channel_id: int) -> bool: 26 | doc = await self.join_requests.find_one({"user_id": user_id}) 27 | return bool(doc and channel_id in doc.get("channels", [])) 28 | 29 | async def del_join_req(self): 30 | await self.join_requests.drop() 31 | 32 | tb = TechifyBots() 33 | 34 | def is_auth_req_channel(_, __, update): 35 | return update.chat.id in AUTH_REQ_CHANNELS 36 | 37 | @Client.on_chat_join_request(filters.create(is_auth_req_channel)) 38 | async def join_reqs(client: Client, message: ChatJoinRequest): 39 | await tb.add_join_req(message.from_user.id, message.chat.id) 40 | 41 | @Client.on_message(filters.command("delreq") & filters.private & filters.user(ADMIN)) 42 | async def del_requests(client: Client, message: Message): 43 | await tb.del_join_req() 44 | await message.reply("**⚙ Successfully join request cache deleted.**") 45 | 46 | async def is_subscribed(bot: Client, user_id: int, expire_at): 47 | missing = [] 48 | for channel_id in AUTH_CHANNELS: 49 | try: 50 | await bot.get_chat_member(channel_id, user_id) 51 | except UserNotParticipant: 52 | try: 53 | chat = await bot.get_chat(channel_id) 54 | invite = await bot.create_chat_invite_link(channel_id, expire_date=expire_at) 55 | missing.append((chat.title, invite.invite_link)) 56 | except ChatAdminRequired: 57 | logging.error(f"Bot not admin in auth channel {channel_id}") 58 | except Exception: 59 | pass 60 | except Exception: 61 | pass 62 | return missing 63 | 64 | async def is_req_subscribed(bot: Client, user_id: int, expire_at): 65 | missing = [] 66 | for channel_id in AUTH_REQ_CHANNELS: 67 | if await tb.has_joined_channel(user_id, channel_id): 68 | continue 69 | try: 70 | chat = await bot.get_chat(channel_id) 71 | invite = await bot.create_chat_invite_link(channel_id, creates_join_request=True, expire_date=expire_at) 72 | missing.append((chat.title, invite.invite_link)) 73 | except ChatAdminRequired: 74 | logging.error(f"Bot not admin in request channel {channel_id}") 75 | except Exception: 76 | pass 77 | return missing 78 | 79 | async def get_fsub(bot: Client, message: Message) -> bool: 80 | user_id = message.from_user.id 81 | if user_id == ADMIN: 82 | return True 83 | expire_at = datetime.datetime.utcnow() + datetime.timedelta(minutes=FSUB_EXPIRE) if FSUB_EXPIRE > 0 else None 84 | missing = [] 85 | if AUTH_CHANNELS: 86 | missing.extend(await is_subscribed(bot, user_id, expire_at)) 87 | if AUTH_REQ_CHANNELS: 88 | missing.extend(await is_req_subscribed(bot, user_id, expire_at)) 89 | if not missing: 90 | return True 91 | bot_user = await bot.get_me() 92 | buttons = [] 93 | for i in range(0, len(missing), 2): 94 | row = [] 95 | for j in range(2): 96 | if i + j < len(missing): 97 | title, link = missing[i + j] 98 | row.append(InlineKeyboardButton(f"{i + j + 1}. {title}", url=link)) 99 | buttons.append(row) 100 | buttons.append([InlineKeyboardButton("🔄 Try Again", url=f"https://telegram.me/{bot_user.username}?start=start")]) 101 | await message.reply(f"**🎭 {message.from_user.mention}, You haven’t joined my channel yet.\nPlease join using the buttons below.**", reply_markup=InlineKeyboardMarkup(buttons)) 102 | return False 103 | 104 | @Client.on_message(filters.private & ~filters.user(ADMIN), group=-10) 105 | async def global_fsub_checker(client: Client, message: Message): 106 | if not IS_FSUB: 107 | return 108 | await get_fsub(client, message) -------------------------------------------------------------------------------- /TechifyBots/commands.py: -------------------------------------------------------------------------------- 1 | import random 2 | import re 3 | from pyrogram import Client, filters 4 | from pyrogram.errors import FloodWait, UserIsBlocked, PeerIdInvalid, InputUserDeactivated 5 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup 6 | from config import * 7 | import asyncio 8 | from Script import text 9 | from .db import tb 10 | from collections import defaultdict 11 | 12 | def parse_button_markup(text: str): 13 | lines = text.split("\n") 14 | buttons = [] 15 | final_text_lines = [] 16 | for line in lines: 17 | row = [] 18 | parts = line.split("||") 19 | is_button_line = True 20 | for part in parts: 21 | match = re.fullmatch(r"\[(.+?)\]\((https?://[^\s]+)\)", part.strip()) 22 | if match: 23 | row.append(InlineKeyboardButton(match[1], url=match[2])) 24 | else: 25 | is_button_line = False 26 | break 27 | if is_button_line and row: 28 | buttons.append(row) 29 | else: 30 | final_text_lines.append(line) 31 | return InlineKeyboardMarkup(buttons) if buttons else None, "\n".join(final_text_lines).strip() 32 | 33 | @Client.on_message(filters.command("start")) 34 | async def start_cmd(client, message): 35 | if await tb.get_user(message.from_user.id) is None: 36 | await tb.add_user(message.from_user.id, message.from_user.first_name) 37 | bot = await client.get_me() 38 | await client.send_message( 39 | LOG_CHANNEL, 40 | text.LOG.format( 41 | message.from_user.id, 42 | getattr(message.from_user, "dc_id", "N/A"), 43 | message.from_user.first_name or "N/A", 44 | f"@{message.from_user.username}" if message.from_user.username else "N/A", 45 | bot.username 46 | ) 47 | ) 48 | await message.reply_photo( 49 | photo=random.choice(PICS), 50 | caption=text.START.format(message.from_user.mention), 51 | reply_markup=InlineKeyboardMarkup([ 52 | [InlineKeyboardButton('⇆ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖦𝗋𝗈𝗎𝗉 ⇆', url='https://telegram.me/QuickReactRobot?startgroup=botstart')], 53 | [InlineKeyboardButton('ℹ️ 𝖠𝖻𝗈𝗎𝗍', callback_data='about'), 54 | InlineKeyboardButton('📚 𝖧𝖾𝗅𝗉', callback_data='help')], 55 | [InlineKeyboardButton('⇆ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖢𝗁𝖺𝗇𝗇𝖾𝗅 ⇆', url='https://telegram.me/QuickReactRobot?startchannel=botstart')] 56 | ]) 57 | ) 58 | 59 | @Client.on_message(filters.command("help") & filters.private) 60 | async def help_cmd(client, message): 61 | reply = await message.reply( 62 | text=("❓ 𝘏𝘢𝘷𝘪𝘯𝘨 𝘛𝘳𝘰𝘶𝘣𝘭𝘦?\n\n𝘐𝘧 𝘺𝘰𝘶'𝘳𝘦 𝘧𝘢𝘤𝘪𝘯𝘨 𝘢𝘯𝘺 𝘱𝘳𝘰𝘣𝘭𝘦𝘮 𝘸𝘩𝘪𝘭𝘦 𝘶𝘴𝘪𝘯𝘨 𝘵𝘩𝘦 𝘣𝘰𝘵 𝘰𝘳 𝘪𝘵𝘴 𝘤𝘰𝘮𝘮𝘢𝘯𝘥𝘴, 𝘱𝘭𝘦𝘢𝘴𝘦 𝘸𝘢𝘵𝘤𝘩 𝘵𝘩𝘦 𝘵𝘶𝘵𝘰𝘳𝘪𝘢𝘭 𝘷𝘪𝘥𝘦𝘰 𝘣𝘦𝘭𝘰𝘸.\n\n🎥 𝘛𝘩𝘦 𝘷𝘪𝘥𝘦𝘰 𝘸𝘪𝘭𝘭 𝘤𝘭𝘦𝘢𝘳𝘭𝘺 𝘦𝘹𝘱𝘭𝘢𝘪𝘯 𝘩𝘰𝘸 𝘵𝘰 𝘶𝘴𝘦 𝘦𝘢𝘤𝘩 𝘧𝘦𝘢𝘵𝘶𝘳𝘦 𝘸𝘪𝘵𝘩 𝘦𝘢𝘴𝘦.\n\n💖 𝘍𝘰𝘳 𝘮𝘰𝘳𝘦 𝘶𝘱𝘥𝘢𝘵𝘦𝘴 — 𝘚𝘶𝘱𝘱𝘰𝘳𝘵 𝘜𝘴." 63 | ), 64 | reply_markup=InlineKeyboardMarkup([ 65 | [InlineKeyboardButton("🎬 𝘞𝘢𝘵𝘤𝘩 𝘛𝘶𝘵𝘰𝘳𝘪𝘢𝘭", url="https://youtu.be/rOnzfDdYqnc")] 66 | ]) 67 | ) 68 | await asyncio.sleep(300) 69 | await reply.delete() 70 | try: 71 | await message.delete() 72 | except: 73 | pass 74 | 75 | @Client.on_message(filters.command("stats") & filters.private & filters.user(ADMIN)) 76 | async def total_users(client: Client, message: Message): 77 | try: 78 | users = await tb.get_all_users() 79 | await message.reply_text(f"👥 **Total Users:** {len(users)}",reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🎭 𝖢𝗅𝗈𝗌𝖾", callback_data="close")]])) 80 | except Exception as e: 81 | r=await message.reply(f"❌ *Error:* `{str(e)}`") 82 | await asyncio.sleep(30) 83 | await r.delete() 84 | 85 | @Client.on_message(filters.group | filters.channel) 86 | async def send_reaction(client: Client, msg: Message): 87 | try: 88 | await msg.react(random.choice(EMOJIS)) 89 | except FloodWait as e: 90 | print(f"FloodWait: Sleeping for {e.value} seconds") 91 | await asyncio.sleep(e.value) 92 | await msg.react(random.choice(EMOJIS)) 93 | except Exception as e: 94 | print(f"Error: {e}") 95 | 96 | @Client.on_message(filters.command("broadcast") & filters.private & filters.user(ADMIN)) 97 | async def broadcasting_func(client: Client, message: Message): 98 | if not message.reply_to_message: 99 | return await message.reply("Reply to a message to broadcast.") 100 | msg = await message.reply_text("📢 Starting broadcast...") 101 | to_copy_msg = message.reply_to_message 102 | users_list = await tb.get_all_users() 103 | total_before = len(users_list) 104 | completed_users = set() 105 | failed = 0 106 | raw_text = to_copy_msg.caption or to_copy_msg.text or "" 107 | reply_markup, cleaned_text = parse_button_markup(raw_text) 108 | 109 | for i, user in enumerate(users_list, start=1): 110 | user_id = user.get("user_id") 111 | if not user_id: 112 | if await tb.delete_user(user.get("_id")): 113 | failed += 1 114 | continue 115 | try: 116 | user_id = int(user_id) # normalize to int 117 | if to_copy_msg.text: 118 | await client.send_message(user_id, cleaned_text, reply_markup=reply_markup) 119 | elif to_copy_msg.photo: 120 | await client.send_photo(user_id, to_copy_msg.photo.file_id, caption=cleaned_text, reply_markup=reply_markup) 121 | elif to_copy_msg.video: 122 | await client.send_video(user_id, to_copy_msg.video.file_id, caption=cleaned_text, reply_markup=reply_markup) 123 | elif to_copy_msg.document: 124 | await client.send_document(user_id, to_copy_msg.document.file_id, caption=cleaned_text, reply_markup=reply_markup) 125 | else: 126 | await to_copy_msg.copy(user_id) 127 | 128 | completed_users.add(user_id) 129 | 130 | except (UserIsBlocked, PeerIdInvalid, InputUserDeactivated): 131 | if await tb.delete_user(user_id): 132 | failed += 1 133 | except FloodWait as e: 134 | await asyncio.sleep(e.value) 135 | try: 136 | await to_copy_msg.copy(user_id) 137 | completed_users.add(user_id) 138 | except Exception: 139 | if await tb.delete_user(user_id): 140 | failed += 1 141 | except Exception: 142 | if await tb.delete_user(user_id): 143 | failed += 1 144 | if i % 20 == 0 or i == total_before: 145 | try: 146 | await msg.edit( 147 | f"😶‍🌫 Broadcasting...\n\n" 148 | f"👥 Total Users: {total_before}\n" 149 | f"✅ Successful: {len(completed_users)}\n" 150 | f"❌ Failed/Removed: {failed}\n" 151 | f"⚙️ Progress: {i}/{total_before}" 152 | ) 153 | except Exception: 154 | pass 155 | 156 | await asyncio.sleep(0.05) 157 | 158 | all_users = await tb.get_all_users() 159 | users_by_id = defaultdict(list) 160 | for user in all_users: 161 | uid = user.get("user_id") 162 | if not uid: 163 | if await tb.delete_user(user.get("_id")): 164 | failed += 1 165 | continue 166 | users_by_id[uid].append(user) 167 | 168 | for uid, docs in users_by_id.items(): 169 | if uid in completed_users: 170 | for duplicate in docs[1:]: 171 | if await tb.delete_user(duplicate.get("user_id")): 172 | failed += 1 173 | else: 174 | for doc in docs: 175 | if await tb.delete_user(doc.get("user_id")): 176 | failed += 1 177 | 178 | active_users = len(completed_users) 179 | 180 | await msg.edit( 181 | f"🎯 Broadcast Completed\n\n" 182 | f"👥 Total Users (Before): {total_before}\n" 183 | f"✅ Successful: {len(completed_users)}\n" 184 | f"❌ Failed/Removed: {failed}\n" 185 | f"📊 Active Users (Now): {active_users}", 186 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🎭 Close", callback_data="close")]]), 187 | ) --------------------------------------------------------------------------------