diff --git a/misc/tdel.py b/misc/tdel.py
new file mode 100644
index 0000000..2e203ad
--- /dev/null
+++ b/misc/tdel.py
@@ -0,0 +1,78 @@
+import asyncio
+from pyrogram import Client, filters, enums
+from pyrogram.types import Message
+from utils.misc import modules_help, prefix
+
+@Client.on_message(filters.command("tdel", prefix) & filters.me)
+async def tdel_message(_, message: Message):
+ if len(message.command) <= 2:
+ await message.edit(
+ "Error: You must specify time (seconds) and message text\n"
+ "Example: .tdel 10 Hello everyone!",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ await asyncio.sleep(5)
+ await message.delete()
+ return
+
+ try:
+ delete_time = int(message.command[1])
+ text = " ".join(message.command[2:])
+
+ if delete_time <= 0:
+ await message.edit(
+ "Error: Time must be a positive number!",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ await asyncio.sleep(3)
+ await message.delete()
+ return
+
+ if delete_time > 86400:
+ await message.edit(
+ "Error: Maximum time is 24 hours (86400 seconds)!",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ await asyncio.sleep(5)
+ await message.delete()
+ return
+
+ if not text.strip():
+ await message.edit(
+ "Error: Message text cannot be empty!",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ await asyncio.sleep(3)
+ await message.delete()
+ return
+
+ await message.edit(
+ text,
+ parse_mode=enums.ParseMode.HTML,
+ )
+
+ await asyncio.sleep(delete_time)
+ await message.delete()
+
+ except ValueError:
+ await message.edit(
+ "Error: Time must be an integer!\n"
+ "Example: .tdel 30 This message will be deleted in 30 seconds",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ await asyncio.sleep(5)
+ await message.delete()
+ except Exception as e:
+ await message.edit(
+ f"Unexpected error: {str(e)}",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ await asyncio.sleep(5)
+ await message.delete()
+
+modules_help["timed_delete"] = {
+ "tdel [time] [text]*": "send self-deleting message\n"
+ "time: seconds until deletion\n"
+ "text: message content\n"
+ "example: .tdel 60 this message will delete in one minute"
+}
diff --git a/utils/anon.py b/utils/anon.py
new file mode 100644
index 0000000..440c6b5
--- /dev/null
+++ b/utils/anon.py
@@ -0,0 +1,73 @@
+from pyrogram import Client, filters, enums
+from pyrogram.types import Message
+from pyrogram.errors import FloodWait, ChannelInvalid, PeerIdInvalid
+from utils.misc import modules_help, prefix
+
+@Client.on_message(filters.command("anon", prefix) & filters.me)
+async def anon(client: Client, message: Message):
+ if len(message.command) < 2:
+ await message.edit(
+ "Usage: anon [channel_id] [message] or reply to a message to forward it.",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ return
+
+ try:
+ source_chat_id = message.chat.id
+ anon_channel_id = int(message.command[1])
+ text_content = " ".join(message.command[2:]) if len(message.command) > 2 else None
+ except (ValueError, IndexError):
+ await message.edit(
+ "Error: Invalid command format. Use anon [channel_id] [text]",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ return
+
+ replied_to_message = message.reply_to_message
+
+ if not replied_to_message and not text_content:
+ await message.edit(
+ "Error: You must provide text or reply to a message/media.",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ return
+
+ original_message_id = message.id
+
+ try:
+ await message.delete()
+
+ if replied_to_message:
+ sent_message = await replied_to_message.copy(anon_channel_id)
+ else:
+ sent_message = await client.send_message(
+ chat_id=anon_channel_id,
+ text=text_content,
+ parse_mode=enums.ParseMode.MARKDOWN,
+ )
+
+ await sent_message.forward(source_chat_id)
+
+ except (ChannelInvalid, PeerIdInvalid):
+ await client.send_message(
+ chat_id=source_chat_id,
+ text=f"Error: The ID {anon_channel_id} is invalid or I am not an admin in that channel.",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ except FloodWait as e:
+ await client.send_message(
+ chat_id=source_chat_id,
+ text=f"FloodWait: Please wait for {e.value} seconds.",
+ parse_mode=enums.ParseMode.HTML,
+ )
+ except Exception as e:
+ await client.send_message(
+ chat_id=source_chat_id,
+ text=f"An unexpected error occurred:\n{e}",
+ parse_mode=enums.ParseMode.HTML,
+ )
+
+modules_help["anonymizer"] = {
+ "anon [id] [message]": "Sends a text message to the specified channel/group ID and then forwards it to the current chat, hiding the original sender. The original command is deleted.",
+ "anon [id] (as reply)": "Copies the replied-to message/media to the specified channel/group ID and then forwards it to the current chat, hiding the original sender. The original command is deleted.",
+}
diff --git a/utils/fidsend.py b/utils/fidsend.py
new file mode 100644
index 0000000..81e7861
--- /dev/null
+++ b/utils/fidsend.py
@@ -0,0 +1,46 @@
+import asyncio
+from pyrogram import Client, filters, enums
+from pyrogram.types import Message
+from utils.misc import modules_help, prefix
+
+@Client.on_message(filters.command("fidsend", prefix) & filters.me)
+async def fidsend(_, message: Message):
+ if len(message.command) <= 1:
+ return
+
+ file_id = " ".join(message.command[1:])
+
+ try:
+ try:
+ await message.reply_photo(file_id)
+ except:
+ try:
+ await message.reply_video(file_id)
+ except:
+ try:
+ await message.reply_sticker(file_id)
+ except:
+ try:
+ await message.reply_voice(file_id)
+ except:
+ try:
+ await message.reply_video_note(file_id)
+ except:
+ try:
+ await message.reply_audio(file_id)
+ except:
+ try:
+ await message.reply_animation(file_id)
+ except:
+ await message.reply_document(file_id)
+
+ await message.delete()
+ except Exception as e:
+ await message.edit(
+ f"Error: {e}",
+ parse_mode=enums.ParseMode.HTML,
+ )
+
+modules_help["file_sender"] = {
+ "fidsend [file_id]*": "send any media file using its file ID\nSupports: photo, video, sticker, voice, video note, audio, animation, document"
+}
\ No newline at end of file
diff --git a/utils/numsend.py b/utils/numsend.py
new file mode 100644
index 0000000..ad85e14
--- /dev/null
+++ b/utils/numsend.py
@@ -0,0 +1,42 @@
+import asyncio
+from pyrogram import Client, filters, enums
+from pyrogram.types import Message
+from utils.misc import modules_help, prefix
+
+@Client.on_message(filters.command("numsend", prefix) & filters.me)
+async def numsend(client: Client, message: Message):
+ if len(message.command) <= 2:
+ return
+
+ try:
+ user_id = int(message.command[1])
+ text = " ".join(message.command[2:])
+
+ if message.reply_to_message:
+ if message.reply_to_message.media:
+ await client.copy_message(
+ chat_id=user_id,
+ from_chat_id=message.chat.id,
+ message_id=message.reply_to_message.id,
+ caption=text if text else None
+ )
+ else:
+ await client.send_message(
+ chat_id=user_id,
+ text=text if text else message.reply_to_message.text
+ )
+ else:
+ await client.send_message(chat_id=user_id, text=text)
+
+ await message.delete()
+
+ except ValueError:
+ await message.edit("Invalid user ID format", parse_mode=enums.ParseMode.HTML)
+ except Exception as e:
+ await message.edit(f"Error: {e}", parse_mode=enums.ParseMode.HTML)
+
+modules_help["numsend"] = {
+ "numsend [user_id] [message]*": "send message to user by numeric ID\n"
+ "Reply to media to forward it with optional caption\n"
+ "Original message will be deleted after sending"
+}
diff --git a/utils/online.py b/utils/online.py
new file mode 100644
index 0000000..07d7f96
--- /dev/null
+++ b/utils/online.py
@@ -0,0 +1,174 @@
+import asyncio
+from pyrogram import Client, filters, enums
+from pyrogram.types import Message
+from datetime import datetime, timedelta
+from utils.misc import modules_help, prefix
+import re
+
+online_task = None
+
+def parse_time_duration(time_str):
+ relative_pattern = r'^(\d+)(s|min|h|m)$'
+ match = re.match(relative_pattern, time_str.lower())
+
+ if match:
+ value = int(match.group(1))
+ unit = match.group(2)
+
+ if unit == 's':
+ return value
+ elif unit == 'min':
+ return value * 60
+ elif unit == 'h':
+ return value * 3600
+ elif unit == 'm': # month
+ return value * 30 * 24 * 3600
+
+ absolute_pattern = r'^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2})$'
+ match = re.match(absolute_pattern, time_str)
+
+ if match:
+ year = int(match.group(1))
+ month = int(match.group(2))
+ day = int(match.group(3))
+ hour = int(match.group(4))
+ minute = int(match.group(5))
+
+ if hour >= 24:
+ hour = 23
+ if minute >= 60:
+ minute = 59
+
+ try:
+ target_time = datetime(year, month, day, hour, minute)
+ current_time = datetime.now()
+
+ if target_time <= current_time:
+ return None # Time has already passed
+
+ delta = target_time - current_time
+ return int(delta.total_seconds())
+ except ValueError:
+ return None
+
+ return None
+
+async def keep_online(duration):
+ try:
+ await asyncio.sleep(duration)
+ except asyncio.CancelledError:
+ pass
+
+def format_time_remaining(seconds):
+ if seconds < 60:
+ return f"{seconds} seconds"
+ elif seconds < 3600:
+ minutes = seconds // 60
+ return f"{minutes} minutes"
+ elif seconds < 86400:
+ hours = seconds // 3600
+ minutes = (seconds % 3600) // 60
+ return f"{hours} hours and {minutes} minutes"
+ else:
+ days = seconds // 86400
+ hours = (seconds % 86400) // 3600
+ return f"{days} days and {hours} hours"
+
+@Client.on_message(filters.command("onl", prefix) & filters.me)
+async def online_keeper(client: Client, message: Message):
+ global online_task
+
+ if len(message.command) <= 1:
+ if online_task and not online_task.done():
+ await message.edit(
+ "đĸ Account is currently being kept online.\n"
+ "Use the /onl stop command to stop.",
+ parse_mode=enums.ParseMode.HTML
+ )
+ else:
+ await message.edit(
+ "đ´ Account is not in auto-online mode.\n"
+ "Example usage:\n"
+ "/onl 30min - for 30 minutes\n"
+ "/onl 2h - for 2 hours\n"
+ "/onl 2025-12-31 23:59 - until a specific date",
+ parse_mode=enums.ParseMode.HTML
+ )
+ return
+
+ time_arg = " ".join(message.command[1:])
+
+ if time_arg.lower() == "stop":
+ if online_task and not online_task.done():
+ online_task.cancel()
+ await message.edit(
+ "âšī¸ Online keeping has been stopped.",
+ parse_mode=enums.ParseMode.HTML
+ )
+ else:
+ await message.edit(
+ "â No online keeping process is active.",
+ parse_mode=enums.ParseMode.HTML
+ )
+ return
+
+ duration = parse_time_duration(time_arg)
+
+ if duration is None:
+ await message.edit(
+ "â Invalid time format!\n\n"
+ "Valid formats:\n"
+ "âĸ 10s - 10 seconds\n"
+ "âĸ 30min - 30 minutes\n"
+ "âĸ 2h - 2 hours\n"
+ "âĸ 1m - 1 month\n"
+ "âĸ 2025-12-31 23:59 - until a specific date\n"
+ "âĸ stop - to stop the process",
+ parse_mode=enums.ParseMode.HTML
+ )
+ return
+
+ max_duration = 30 * 24 * 3600 # 30 days
+ if duration > max_duration:
+ await message.edit(
+ "â ī¸ The maximum allowed duration is 30 days.",
+ parse_mode=enums.ParseMode.HTML
+ )
+ return
+
+ if online_task and not online_task.done():
+ online_task.cancel()
+
+ online_task = asyncio.create_task(keep_online(duration))
+
+ time_formatted = format_time_remaining(duration)
+
+ await message.edit(
+ f"đĸ Account will be kept online.\n"
+ f"âąī¸ Duration: {time_formatted}\n"
+ f"đ§ Argument: {time_arg}\n\n"
+ f"To stop: {prefix}onl stop",
+ parse_mode=enums.ParseMode.HTML
+ )
+
+ try:
+ await online_task
+ await client.send_message(
+ message.chat.id,
+ "â° The online keeping period has ended.",
+ parse_mode=enums.ParseMode.HTML
+ )
+ except asyncio.CancelledError:
+ pass
+
+modules_help["online_keeper"] = {
+ "onl": "Display online status",
+ "onl [time]*": "Keep account online for a specified duration.\n"
+ "Time formats:\n"
+ "âĸ 10s - 10 seconds\n"
+ "âĸ 30min - 30 minutes\n"
+ "âĸ 2h - 2 hours\n"
+ "âĸ 1m - 1 month\n"
+ "âĸ 2025-12-31 23:59 - until a specific date",
+ "onl stop": "Stop keeping the account online"
+}
diff --git a/utils/raw.py b/utils/raw.py
new file mode 100644
index 0000000..952ba37
--- /dev/null
+++ b/utils/raw.py
@@ -0,0 +1,147 @@
+from pyrogram import Client, filters, enums
+from pyrogram.types import Message
+import json
+from utils.misc import modules_help, prefix
+
+def send_chunked_messages(client, data, chat_id="me"):
+ chunk_size = 4080
+
+ if len(data) <= chunk_size:
+ return [f"```json\n{data}\n```"]
+
+ chunks = []
+ for i in range(0, len(data), chunk_size):
+ chunk = data[i:i+chunk_size]
+ chunks.append(f"```json\n{chunk}\n```")
+
+ return chunks
+
+@Client.on_message(filters.command("raw", prefix) & filters.me)
+async def get_raw_message(client: Client, message: Message):
+ if not message.reply_to_message:
+ await message.delete()
+ return
+
+ raw_data = str(message.reply_to_message)
+ json_data = json.dumps(json.loads(raw_data), indent=2, ensure_ascii=False)
+
+ chunks = send_chunked_messages(client, json_data)
+
+ for chunk in chunks:
+ await client.send_message("me", chunk, parse_mode=enums.ParseMode.MARKDOWN)
+
+ await message.delete()
+
+@Client.on_message(filters.command("uraw", prefix) & filters.me)
+async def get_user_raw_data(client: Client, message: Message):
+ target_user = None
+
+ if message.reply_to_message:
+ target_user = message.reply_to_message.from_user
+
+ elif message.entities:
+ for entity in message.entities:
+ if entity.type == enums.MessageEntityType.MENTION:
+ username = message.text[entity.offset:entity.offset + entity.length].replace('@', '')
+ try:
+ target_user = await client.get_users(username)
+ except:
+ continue
+ elif entity.type == enums.MessageEntityType.TEXT_MENTION:
+ target_user = entity.user
+
+ if not target_user:
+ await message.edit("No user found to extract data. Reply to a message or mention a user.")
+ return
+
+ try:
+ full_user = await client.get_users(target_user.id)
+ raw_data = str(full_user)
+ json_data = json.dumps(json.loads(raw_data), indent=2, ensure_ascii=False)
+
+ chunks = send_chunked_messages(client, json_data)
+
+ for chunk in chunks:
+ await client.send_message("me", chunk, parse_mode=enums.ParseMode.MARKDOWN)
+
+ await message.delete()
+
+ except Exception as e:
+ await message.edit(f"Error getting user data: {str(e)}")
+
+@Client.on_message(filters.command("picraw", prefix) & filters.me)
+async def get_profile_pics_raw(client: Client, message: Message):
+ target_user = None
+
+ if message.reply_to_message:
+ target_user = message.reply_to_message.from_user
+
+ elif message.entities:
+ for entity in message.entities:
+ if entity.type == enums.MessageEntityType.MENTION:
+ username = message.text[entity.offset:entity.offset + entity.length].replace('@', '')
+ try:
+ target_user = await client.get_users(username)
+ except:
+ continue
+ elif entity.type == enums.MessageEntityType.TEXT_MENTION:
+ target_user = entity.user
+
+ if not target_user:
+ await message.edit("No user found to extract photos. Reply to a message or mention a user.")
+ return
+
+ try:
+ photos = []
+ async for photo in client.get_chat_photos(target_user.id):
+ photos.append(photo)
+
+ if not photos:
+ await message.edit("This user has no profile photos.")
+ return
+
+ photo_data = []
+ for i, photo in enumerate(photos):
+ photo_info = {
+ "index": i + 1,
+ "file_id": photo.file_id,
+ "file_unique_id": photo.file_unique_id,
+ "date": photo.date.isoformat() if photo.date else None,
+ "sizes": []
+ }
+
+ for size in photo.thumbs:
+ size_info = {
+ "type": size.type if hasattr(size, 'type') else "unknown",
+ "width": size.width if hasattr(size, 'width') else None,
+ "height": size.height if hasattr(size, 'height') else None,
+ "file_size": size.file_size if hasattr(size, 'file_size') else None
+ }
+ photo_info["sizes"].append(size_info)
+
+ photo_data.append(photo_info)
+
+ json_data = json.dumps({
+ "user_id": target_user.id,
+ "username": target_user.username,
+ "first_name": target_user.first_name,
+ "last_name": target_user.last_name,
+ "total_photos": len(photos),
+ "photos": photo_data
+ }, indent=2, ensure_ascii=False)
+
+ chunks = send_chunked_messages(client, json_data)
+
+ for chunk in chunks:
+ await client.send_message("me", chunk, parse_mode=enums.ParseMode.MARKDOWN)
+
+ await message.delete()
+
+ except Exception as e:
+ await message.edit(f"Error getting profile photos: {str(e)}")
+
+modules_help["raw_json"] = {
+ "raw [reply]": "Get raw JSON data of replied message and send to saved messages",
+ "uraw [reply/mention]": "Get raw user data from replied or mentioned user",
+ "picraw [reply/mention]": "Get file_id of all profile pictures from user",
+}
diff --git a/utils/tagall.py b/utils/tagall.py
index 518ef96..ad92a66 100644
--- a/utils/tagall.py
+++ b/utils/tagall.py
@@ -1,32 +1,192 @@
import asyncio
+from typing import List, Optional
from pyrogram import Client, filters, enums
-from pyrogram.types import Message
+from pyrogram.types import Message, ChatMember
+from pyrogram.errors import FloodWait, ChatAdminRequired, UserNotParticipant
from utils.misc import modules_help, prefix
+class TaggerBot:
+ def __init__(self, batch_size: int = 5, delay: float = 2.0):
+ self.batch_size = batch_size
+ self.delay = delay
+
+ async def get_members_by_role(
+ self,
+ client: Client,
+ chat_id: int,
+ admin_only: bool = False,
+ max_members: Optional[int] = None
+ ) -> List[ChatMember]:
+ members = []
+ count = 0
+
+ try:
+ async for member in client.get_chat_members(chat_id):
+ if max_members and count >= max_members:
+ break
+
+ if admin_only:
+ if member.status in [
+ enums.ChatMemberStatus.OWNER,
+ enums.ChatMemberStatus.ADMINISTRATOR
+ ]:
+ members.append(member)
+ count += 1
+ else:
+ if not member.user.is_bot and not member.user.is_deleted:
+ members.append(member)
+ count += 1
+
+ except UserNotParticipant:
+ print("Bot is not a member of this chat!")
+ except Exception as e:
+ print(f"Error fetching members: {e}")
+
+ return members
+
+ async def send_batch_tags(
+ self,
+ client: Client,
+ chat_id: int,
+ members: List[ChatMember]
+ ) -> bool:
+ if not members:
+ return False
+
+ for i in range(0, len(members), self.batch_size):
+ batch = members[i:i + self.batch_size]
+ tags = []
+
+ for member in batch:
+ if member.user.username:
+ tags.append(f"@{member.user.username}")
+ else:
+ tags.append(member.user.mention)
+
+ if tags:
+ message_text = "\n".join(tags)
+ try:
+ await client.send_message(
+ chat_id,
+ text=message_text,
+ parse_mode=enums.ParseMode.HTML
+ )
+
+ if i + self.batch_size < len(members):
+ await asyncio.sleep(self.delay)
+
+ except FloodWait as e:
+ await asyncio.sleep(e.value + 1)
+ continue
+ except Exception as e:
+ print(f"Error sending batch {i//self.batch_size + 1}: {e}")
+ continue
+
+ return True
+
+
+tagger = TaggerBot(batch_size=5, delay=2.0)
+
+
@Client.on_message(filters.command("tagall", prefix) & filters.me)
async def tagall(client: Client, message: Message):
await message.delete()
- chat_id = message.chat.id
- string = ""
- limit = 1
- icm = client.get_chat_members(chat_id)
- async for member in icm:
- tag = member.user.username
- if limit <= 5:
- string += f"@{tag}\n" if tag != None else f"{member.user.mention}\n"
- limit += 1
+
+ if message.chat.type == enums.ChatType.PRIVATE:
+ await client.send_message(
+ message.chat.id,
+ "â This command only works in groups and supergroups!"
+ )
+ return
+
+ status_msg = await client.send_message(
+ message.chat.id,
+ "đ Fetching member list..."
+ )
+
+ try:
+ members = await tagger.get_members_by_role(
+ client,
+ message.chat.id,
+ admin_only=False,
+ max_members=200
+ )
+
+ if not members:
+ await status_msg.edit("â No active members found!")
+ return
+
+ await status_msg.edit(f"đˇ Starting to tag {len(members)} members...")
+
+ success = await tagger.send_batch_tags(client, message.chat.id, members)
+
+ if success:
+ await status_msg.edit(f"â
Successfully tagged {len(members)} members!")
else:
- await client.send_message(
- chat_id, text=string, parse_mode=enums.ParseMode.HTML
- )
- limit = 1
- string = ""
- await asyncio.sleep(2)
+ await status_msg.edit("â Error tagging members!")
+
+ except ChatAdminRequired:
+ await status_msg.edit("â I need to be a group admin to execute this command!")
+ except Exception as e:
+ await status_msg.edit(f"â Command execution error: {str(e)}")
+
+
+@Client.on_message(filters.command("tagadmins", prefix) & filters.me)
+async def tagadmins(client: Client, message: Message):
+ await message.delete()
+
+ if message.chat.type == enums.ChatType.PRIVATE:
+ await client.send_message(
+ message.chat.id,
+ "â This command only works in groups and supergroups!"
+ )
+ return
+
+ status_msg = await client.send_message(
+ message.chat.id,
+ "đ Fetching admin list..."
+ )
+
+ try:
+ admins = await tagger.get_members_by_role(
+ client,
+ message.chat.id,
+ admin_only=True
+ )
+
+ if not admins:
+ await status_msg.edit("â No admins found!")
+ return
+
+ await status_msg.edit(f"đˇ Starting to tag {len(admins)} admins...")
+
+ success = await tagger.send_batch_tags(client, message.chat.id, admins)
+
+ if success:
+ await status_msg.edit(f"â
Successfully tagged {len(admins)} admins!")
+ else:
+ await status_msg.edit("â Error tagging admins!")
+
+ except ChatAdminRequired:
+ await status_msg.edit("â I need to be a group admin to execute this command!")
+ except Exception as e:
+ await status_msg.edit(f"â Command execution error: {str(e)}")
+
+
+@Client.on_message(filters.command("tagstop", prefix) & filters.me)
+async def tagstop(client: Client, message: Message):
+ await message.delete()
+ await client.send_message(
+ message.chat.id,
+ "â ī¸ To stop the operation, restart the bot or wait for it to finish"
+ )
modules_help["tagall"] = {
- "tagall": "Tag all members",
+ "tagall": "Tag all active group members (max 200)",
+ "tagadmins": "Tag only admins and group owner",
+ "tagstop": "Instructions to stop tagging operation"
}