├── app.json ├── heroku.yml ├── runtime.txt ├── Procfile ├── start.sh ├── utils ├── __init__.py └── logging_setup.py ├── core ├── __init__.py └── start.py ├── modules ├── __init__.py └── notify.py ├── requirements.txt ├── docker-compose.yml ├── sample.env ├── Dockerfile ├── main.py ├── user.py ├── app.py ├── LICENSE ├── config.py └── README.md /app.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.13 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: bash start.sh -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 main.py -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .logging_setup import LOGGER -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | from .start import setup_start_handler -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .notify import setup_modules_handlers -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrofork 2 | asyncio 3 | python-dotenv 4 | python-dateutil -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | smartmonitor: 3 | build: . 4 | container_name: smartmonitor 5 | ports: 6 | - "8000:8000" 7 | env_file: 8 | - .env 9 | volumes: 10 | - .:/app -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | API_ID=YOUR_API_ID_HERE 2 | API_HASH=YOUR_API_HASH_HERE 3 | BOT_TOKEN=YOUR_BOT_TOKEN_HERE 4 | SESSION_STRING=YOUR_SESSION_STRING_HERE 5 | OWNER_ID=YOUR_USER_ID_HERE 6 | UPDATE_CHANNEL_URL=YOUR_UPDATE_CHANNEL_URL_HERE 7 | CHANNEL_ID=MONITOR_CHANNEL_ID 8 | COMMAND_PREFIX=!|.|#|,|/ 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim-buster 2 | 3 | RUN apt update && apt install -y git curl && apt clean 4 | 5 | WORKDIR /app 6 | 7 | COPY requirements.txt . 8 | RUN pip install --no-cache-dir -r requirements.txt 9 | 10 | COPY . . 11 | 12 | RUN chmod +x start.sh 13 | 14 | EXPOSE 8000 15 | 16 | CMD ["bash", "start.sh"] 17 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from utils import LOGGER 2 | from modules import setup_modules_handlers 3 | from core import setup_start_handler 4 | from app import app 5 | from user import user 6 | 7 | setup_modules_handlers(app) 8 | setup_start_handler(app) 9 | 10 | LOGGER.info("Bot Successfully Started! 💥") 11 | user.start() 12 | app.run() 13 | -------------------------------------------------------------------------------- /user.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | from pyrogram import Client 4 | from utils import LOGGER 5 | from config import SESSION_STRING 6 | 7 | # Initialize User Client 8 | LOGGER.info("Creating User Client From SESSION_STRING") 9 | 10 | user = Client( 11 | "user_session", 12 | session_string=SESSION_STRING, 13 | workers=1000 14 | ) 15 | 16 | LOGGER.info("User Client Successfully Created!") -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | from pyrogram import Client 4 | from utils import LOGGER 5 | from config import ( 6 | API_ID, 7 | API_HASH, 8 | BOT_TOKEN 9 | ) 10 | 11 | LOGGER.info("Creating Bot Client From BOT_TOKEN") 12 | 13 | app = Client( 14 | "SmartTools", 15 | api_id=API_ID, 16 | api_hash=API_HASH, 17 | bot_token=BOT_TOKEN, 18 | workers=1000 19 | ) 20 | 21 | LOGGER.info("Bot Client Created Successfully!") -------------------------------------------------------------------------------- /utils/logging_setup.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from logging.handlers import RotatingFileHandler 3 | 4 | logging.basicConfig( 5 | level=logging.INFO, 6 | format="%(asctime)s - %(levelname)s - %(message)s", 7 | datefmt='%Y-%m-%d %H:%M:%S', 8 | handlers=[ 9 | RotatingFileHandler("botlog.txt", maxBytes=50000000, backupCount=10), 10 | logging.StreamHandler() 11 | ] 12 | ) 13 | 14 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 15 | logging.getLogger("aiohttp").setLevel(logging.ERROR) 16 | logging.getLogger("apscheduler").setLevel(logging.ERROR) 17 | 18 | LOGGER = logging.getLogger(__name__) 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 ISmartCoder 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. -------------------------------------------------------------------------------- /core/start.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message 3 | from pyrogram.enums import ParseMode, ChatType 4 | from config import UPDATE_CHANNEL_URL, COMMAND_PREFIX 5 | 6 | 7 | def setup_start_handler(app: Client): 8 | @app.on_message(filters.command(["start"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 9 | async def start_message(client: Client, message: Message): 10 | chat_id = message.chat.id 11 | 12 | full_name = "User" 13 | if message.from_user: 14 | first_name = message.from_user.first_name or "" 15 | last_name = message.from_user.last_name or "" 16 | full_name = f"{first_name} {last_name}".strip() 17 | 18 | response_text = ( 19 | f"Hi {full_name}! Welcome To This Bot\n" 20 | "━━━━━━━━━━━━━━━━━━━━━━\n" 21 | f"Smart Monitor: The ultimate toolkit on Telegram can monitor any channels or groups actions where he is admin and notify owner.\n" 22 | "━━━━━━━━━━━━━━━━━━━━━━\n" 23 | "Don't Forget To Join Here For Updates!".format(UPDATE_CHANNEL_URL=UPDATE_CHANNEL_URL) 24 | ) 25 | 26 | await client.send_message( 27 | chat_id=chat_id, 28 | text=response_text, 29 | parse_mode=ParseMode.HTML, 30 | reply_markup=InlineKeyboardMarkup([ 31 | [[InlineKeyboardButton("Update Channel", url="UPDATE_CHANNEL_URL")]] 32 | ]), 33 | disable_web_page_preview=True, 34 | ) 35 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dotenv import load_dotenv 3 | 4 | load_dotenv() 5 | 6 | def get_env_or_default(key, default=None, cast_func=str): 7 | value = os.getenv(key) 8 | if value is not None and value.strip() != "": 9 | try: 10 | return cast_func(value) 11 | except (ValueError, TypeError): 12 | return default 13 | return default 14 | 15 | # Load main credentials 16 | API_ID = get_env_or_default("API_ID", cast_func=int) 17 | API_HASH = get_env_or_default("API_HASH") 18 | BOT_TOKEN = get_env_or_default("BOT_TOKEN") 19 | SESSION_STRING = get_env_or_default("SESSION_STRING") 20 | OWNER_ID = get_env_or_default("OWNER_ID", cast_func=int) 21 | CHANNEL_ID = get_env_or_default("CHANNEL_ID", cast_func=int) 22 | 23 | # Load command prefixes 24 | raw_prefixes = get_env_or_default("COMMAND_PREFIX", "!|.|#|,|/") 25 | COMMAND_PREFIX = [prefix.strip() for prefix in raw_prefixes.split("|") if prefix.strip()] 26 | 27 | # Update channel 28 | UPDATE_CHANNEL_URL = get_env_or_default("UPDATE_CHANNEL_URL", "t.me/TheSmartDev") 29 | 30 | # Required variable validation 31 | required_vars = { 32 | "API_ID": API_ID, 33 | "API_HASH": API_HASH, 34 | "BOT_TOKEN": BOT_TOKEN, 35 | "SESSION_STRING": SESSION_STRING, 36 | "OWNER_ID": OWNER_ID, 37 | "CHANNEL_ID": CHANNEL_ID, 38 | } 39 | 40 | for var_name, var_value in required_vars.items(): 41 | if var_value is None or (isinstance(var_value, str) and var_value.strip() == ""): 42 | raise ValueError(f"Required variable {var_name} is missing or invalid.") 43 | 44 | if not COMMAND_PREFIX: 45 | raise ValueError("No command prefixes found. Set COMMAND_PREFIX in .env.") 46 | 47 | print("Loaded COMMAND_PREFIX:", COMMAND_PREFIX) 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔥 SmartMonitorBot 💀👀 2 | 3 | SmartMonitorBot is the ultimate Telegram channel event tracker, crafted with Pyrofork. This beast monitors your supergroups and channels like a cyber hawk, delivering real-time alerts to the owner for every major action. Powered by `Client.get_chat_event_log()`, it’s your go-to for staying in control. Rule your Telegram empire with style! 🚀 4 | 5 | ![Python](https://img.shields.io/badge/Python-3.8+-3776AB.svg?logo=python&logoColor=yellow&style=flat) 6 | ![Pyrofork](https://img.shields.io/badge/Pyrofork-Latest-00CED1.svg?logo=telegram&style=flat) 7 | ![Docker](https://img.shields.io/badge/Docker-Supported-2496ED.svg?logo=docker&logoColor=white&style=flat) 8 | ![Heroku](https://img.shields.io/badge/Heroku-Supported-430098.svg?logo=heroku&style=flat) 9 | ![License](https://img.shields.io/badge/License-MIT-28A745.svg?logo=mit&style=flat) 10 | ![Stars](https://img.shields.io/github/stars/TheSmartDevs/SmartMonitorBot?color=FFD700&logo=github&style=flat) 11 | ![Forks](https://img.shields.io/github/forks/TheSmartDevs/SmartMonitorBot?color=FF4500&logo=github&style=flat) 12 | ![Issues](https://img.shields.io/github/issues/TheSmartDevs/SmartMonitorBot?color=DC143C&logo=github&style=flat) 13 | ![Contributors](https://img.shields.io/github/contributors/TheSmartDevs/SmartMonitorBot?color=32CD32&logo=github&style=flat) 14 | ![Repo Size](https://img.shields.io/github/repo-size/TheSmartDevs/SmartMonitorBot?color=1E90FF&logo=github&style=flat) 15 | 16 | --- 17 | 18 | ## ⚠️ Ethical Use Warning 19 | 20 | This project is open-source under the MIT License, but **do not copy the code** without proper attribution. Instead, **fork the repository** on [GitHub](https://github.com/TheSmartDevs/SmartMonitorBot) and customize it for your needs. If you use any part of this code, **give credit** to [@ISmartCoder](https://github.com/abirxdhack) and link back to this repository. Respect the hustle and keep it ethical! 🙏 21 | 22 | --- 23 | 24 | ## ✨ Epic Features ✅ 25 | 26 | SmartMonitorBot is loaded with features that make it the slickest Telegram monitoring tool: 27 | 28 | - **Instant Alerts**: Get pinged the moment something happens in your channel. No delays, just raw speed. ⚡️ 29 | - **All-Seeing Event Tracking**: Catches every move, including: 30 | - Title, description, username, or photo changes 📝 31 | - Invite, signature, or slow mode toggles 🔄 32 | - Pinned/unpinned messages 📌 33 | - Edited or deleted messages ✏️🗑️ 34 | - Joins, leaves, or invites 👥 35 | - Bans, unbans, admin promotions, or demotions 🚨 36 | - Group calls, sticker sets, linked chats, or location updates 🎙️🌍 37 | - Subscription extensions or pre-history toggles ❄️ 38 | - **One-Command Start**: Hit `/start`, and the bot auto-notifies the owner. Zero hassle. 😎 39 | - **Deployment Nirvana**: Heroku, VPS with `screen`, or Docker—pick your vibe. 🐳 40 | - **Custom Prefixes**: Set prefixes like `!`, `.`, `#`, `,`, or `/` via `.env`. Make it yours. ⚙️ 41 | - **Bulletproof Config**: Validates required env vars to keep things rock-solid. No crashes allowed. 💪 42 | 43 | --- 44 | 45 | ## 💀 Events Watched Like a Boss 46 | 47 | Here’s the full rundown of what SmartMonitorBot tracks (from `EVENT_TYPE_MAP`): 48 | 49 | | Event Type | What’s Happening? | 50 | |------------|-------------------| 51 | | `ChannelAdminLogEventActionChangeTitle` | Channel title got a glow-up | 52 | | `ChannelAdminLogEventActionChangeAbout` | Description revamped | 53 | | `ChannelAdminLogEventActionChangeUsername` | Username switched | 54 | | `ChannelAdminLogEventActionChangePhoto` | New profile pic dropped | 55 | | `ChannelAdminLogEventActionToggleInvites` | Invites flipped on/off | 56 | | `ChannelAdminLogEventActionToggleSignatures` | Signatures toggled | 57 | | `ChannelAdminLogEventActionUpdatePinned` | Message pinned or unpinned | 58 | | `ChannelAdminLogEventActionEditMessage` | Message edited | 59 | | `ChannelAdminLogEventActionDeleteMessage` | Message yeeted | 60 | | `ChannelAdminLogEventActionParticipantJoin` | New member joined the party | 61 | | `ChannelAdminLogEventActionParticipantLeave` | Someone ghosted | 62 | | `ChannelAdminLogEventActionParticipantInvite` | Fresh invite sent | 63 | | `ChannelAdminLogEventActionParticipantToggleBan` | User banned or unbanned | 64 | | `ChannelAdminLogEventActionParticipantToggleAdmin` | Admin promoted or demoted | 65 | | `ChannelAdminLogEventActionChangeStickerSet` | Sticker set swapped | 66 | | `ChannelAdminLogEventActionTogglePreHistoryHidden` | Pre-history visibility toggled | 67 | | `ChannelAdminLogEventActionDefaultBannedRights` | Default banned rights updated | 68 | | `ChannelAdminLogEventActionStartGroupCall` | Group call started | 69 | | `ChannelAdminLogEventActionEndGroupCall` | Group call ended | 70 | | `ChannelAdminLogEventActionChangeLinkedChat` | Linked chat switched | 71 | | `ChannelAdminLogEventActionChangeLocation` | Location updated | 72 | | `ChannelAdminLogEventActionToggleSlowMode` | Slow mode flipped | 73 | | `ChannelAdminLogEventActionToggleSubExtend` | Subscription extension toggled | 74 | 75 | --- 76 | 77 | ## 📂 Project Structure 78 | 79 | Here’s the layout of this masterpiece: 80 | 81 | ``` 82 | SmartMonitorBot/ 83 | ├── core/ # Core bot logic 💻 84 | │ └── start.py 85 | ├── modules/ # Notification magic ✨ 86 | │ ├── notify.py 87 | │ └── __init__.py 88 | ├── utils/ # Utility spells 🛠️ 89 | │ ├── event.py 90 | │ ├── logging_setup.py 91 | │ └── __init__.py 92 | ├── sample.env # Env template 📜 93 | ├── app.json # Heroku config ⚙️ 94 | ├── app.py # App entry point 🚪 95 | ├── config.py # Config wizardry 🪄 96 | ├── docker-compose.yml # Docker setup 🐳 97 | ├── Dockerfile # Docker blueprint 📦 98 | ├── heroku.yml # Heroku deployment 📡 99 | ├── main.py # Main bot engine 🔥 100 | ├── Procfile # Heroku process 📋 101 | ├── requirements.txt # Dependencies list 📦 102 | ├── runtime.txt # Runtime spec ⚡️ 103 | ├── start.sh # Startup script 🏁 104 | ├── user.py # User client logic 👤 105 | └── README.md # This epic guide 📖 106 | ``` 107 | 108 | --- 109 | 110 | ## 🚀 Get It Running 111 | 112 | ### Prerequisites ✅ 113 | - Python 3.8+ (local or VPS) 114 | - Docker & Docker Compose (for containerized deployment) 115 | - Telegram account with admin rights in your supergroup/channel 116 | - API credentials from [my.telegram.org](https://my.telegram.org) 117 | - Bot token from [@BotFather](https://t.me/BotFather) 118 | 119 | ### Setup Steps 👀 120 | 1. **Clone the Repo**: 121 | ```bash 122 | git clone https://github.com/TheSmartDevs/SmartMonitorBot.git 123 | cd SmartMonitorBot 124 | ``` 125 | 126 | 2. **Configure `.env`**: 127 | - Copy the sample: 128 | ```bash 129 | cp sample.env .env 130 | ``` 131 | - Add your credentials: 132 | ``` 133 | API_ID=your_api_id 134 | API_HASH=your_api_hash 135 | BOT_TOKEN=your_bot_token 136 | SESSION_STRING=your_session_string 137 | OWNER_ID=your_user_id 138 | CHANNEL_ID=your_channel_id 139 | UPDATE_CHANNEL_URL=your_update_channel_url 140 | COMMAND_PREFIX=!|.|#|,|/ 141 | ``` 142 | 143 | 3. **Install Dependencies**: 144 | - Local/VPS: 145 | ```bash 146 | pip install -r requirements.txt 147 | ``` 148 | - Docker handles this automatically. 149 | 150 | 4. **Fire It Up**: 151 | - **Local/VPS**: 152 | ```bash 153 | python main.py 154 | ``` 155 | - **VPS with `screen`** (for persistent sessions): 156 | ```bash 157 | screen -S SmartMonitorBot 158 | python main.py 159 | ``` 160 | Detach with `Ctrl+A`, then `D`. Reattach with: 161 | ```bash 162 | screen -r SmartMonitorBot 163 | ``` 164 | - **Docker**: 165 | ```bash 166 | docker compose up --build --remove-orphans 167 | ``` 168 | Stop it with: 169 | ```bash 170 | docker compose down 171 | ``` 172 | 173 | 5. **Activate the Bot**: 174 | - Send `/start` to the bot, and it’ll auto-notify the owner of events. Done deal. ✅ 175 | 176 | --- 177 | 178 | ## 🌐 Deployment Options 179 | 180 | ### Heroku Deployment 🚀 181 | Launch on Heroku with one click: 182 | 183 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/TheSmartDevs/SmartMonitorBot) 184 | 185 | 1. Hit the button above. 186 | 2. Fill in your `.env` vars in Heroku’s dashboard. 187 | 3. Deploy and start owning your channel! 👀 188 | 189 | ### VPS Deployment with `screen` ❄️ 190 | 1. Install Python and `screen`: 191 | ```bash 192 | sudo apt update 193 | sudo apt install python3 python3-pip screen 194 | ``` 195 | 2. Clone the repo and set up `.env`. 196 | 3. Install dependencies: 197 | ```bash 198 | pip install -r requirements.txt 199 | ``` 200 | 4. Run in a `screen` session: 201 | ```bash 202 | screen -S SmartMonitorBot 203 | python main.py 204 | ``` 205 | 5. Detach (`Ctrl+A`, `D`) and check back with: 206 | ```bash 207 | screen -r SmartMonitorBot 208 | ``` 209 | 210 | ### Docker Deployment 🐳 211 | 1. Install Docker & Docker Compose: 212 | ```bash 213 | sudo apt install docker.io docker-compose 214 | ``` 215 | 2. Clone the repo and configure `.env`. 216 | 3. Build and run: 217 | ```bash 218 | docker compose up --build --remove-orphans 219 | ``` 220 | 4. Shut it down: 221 | ```bash 222 | docker compose down 223 | ``` 224 | 225 | --- 226 | 227 | ## 🤝 Contributing 228 | 229 | Want to make this bot even crazier? Fork the repo, customize, and submit PRs at [GitHub](https://github.com/TheSmartDevs/SmartMonitorBot). Keep the code tight, add tests, and respect the ethical warning above. Let’s build something epic together! ✅ 230 | 231 | --- 232 | 233 | ## 📜 License 234 | 235 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 236 | 237 | --- 238 | 239 | ## 📬 Connect 240 | 241 | - **Owner**: [@ISmartCoder](https://github.com/abirxdhack) 💀 242 | - **Update Channel**: [t.me/TheSmartDev](https://t.me/TheSmartDev) 👀 243 | 244 | Monitor like a boss with SmartMonitorBot! 🔥 -------------------------------------------------------------------------------- /modules/notify.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import datetime 3 | from pyrogram import Client, filters 4 | from pyrogram.errors import FloodWait, ChatAdminRequired 5 | from pyrogram.enums import ParseMode 6 | from pyrogram.raw.types import ChannelAdminLogEventsFilter 7 | from pyrogram.raw.functions.channels import GetAdminLog 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message 9 | from app import app 10 | from user import user 11 | from config import CHANNEL_ID, OWNER_ID, UPDATE_CHANNEL_URL 12 | 13 | EVENT_TYPE_MAP = { 14 | "ChannelAdminLogEventActionChangeTitle": "Changed channel title", 15 | "ChannelAdminLogEventActionChangeAbout": "Changed channel description", 16 | "ChannelAdminLogEventActionChangeUsername": "Changed channel username", 17 | "ChannelAdminLogEventActionChangePhoto": "Changed channel photo", 18 | "ChannelAdminLogEventActionToggleInvites": "Toggled invites", 19 | "ChannelAdminLogEventActionToggleSignatures": "Toggled signatures", 20 | "ChannelAdminLogEventActionUpdatePinned": "Pinned/unpinned message", 21 | "ChannelAdminLogEventActionEditMessage": "Edited message", 22 | "ChannelAdminLogEventActionDeleteMessage": "Deleted message", 23 | "ChannelAdminLogEventActionParticipantJoin": "Participant joined", 24 | "ChannelAdminLogEventActionParticipantLeave": "Participant left", 25 | "ChannelAdminLogEventActionParticipantInvite": "Invited participant", 26 | "ChannelAdminLogEventActionParticipantToggleBan": "Banned/unbanned user", 27 | "ChannelAdminLogEventActionParticipantToggleAdmin": "Promoted/demoted admin", 28 | "ChannelAdminLogEventActionChangeStickerSet": "Changed sticker set", 29 | "ChannelAdminLogEventActionTogglePreHistoryHidden": "Toggled pre-history hidden", 30 | "ChannelAdminLogEventActionDefaultBannedRights": "Changed default banned rights", 31 | "ChannelAdminLogEventActionStartGroupCall": "Started group call", 32 | "ChannelAdminLogEventActionEndGroupCall": "Ended group call", 33 | "ChannelAdminLogEventActionChangeLinkedChat": "Changed linked chat", 34 | "ChannelAdminLogEventActionChangeLocation": "Changed location", 35 | "ChannelAdminLogEventActionToggleSlowMode": "Toggled slow mode", 36 | "ChannelAdminLogEventActionToggleSubExtend": "Toggled subscription extension", 37 | } 38 | 39 | def setup_modules_handlers(app): 40 | async def send_notification(event_description, user_name, user_id, channel_id, event_date): 41 | try: 42 | formatted_time = event_date.strftime("%I:%M %p") 43 | formatted_date = event_date.strftime("%d-%m-%Y") 44 | except (ValueError, TypeError) as e: 45 | formatted_time = "Invalid time" 46 | formatted_date = "Invalid date" 47 | print(f"Error formatting event date: {e}") 48 | 49 | chat_id_display = f"{channel_id}" 50 | if "Posted new message" in event_description: 51 | alert_title = "Alert: New Message Posted in Channel" 52 | else: 53 | alert_title = "Alert: Admin Changed Channel Settings" 54 | error_message = ( 55 | f"**🔍 {alert_title} 📋**\n" 56 | "**━━━━━━━━━━━━━━━━**\n" 57 | f"**• COMMAND:** `Admin Action`\n" 58 | f"**• EVENT TYPE:** `{event_description}`\n" 59 | f"**• USER NAME:** `{user_name}`\n" 60 | f"**• USER ID:** `{user_id}`\n" 61 | f"**• CHANNEL ID:** `{chat_id_display}`\n" 62 | f"**• TIME:** `{formatted_time}`\n" 63 | f"**• DATE:** `{formatted_date}`\n" 64 | "**━━━━━━━━━━━━━━━━**\n" 65 | "**🔍 Always Check & Take Action 📋**" 66 | ) 67 | 68 | keyboard = InlineKeyboardMarkup( 69 | [ 70 | [ 71 | InlineKeyboardButton("User's Profile", user_id=user_id if user_id != "N/A" else OWNER_ID), 72 | InlineKeyboardButton("Developer", user_id=OWNER_ID) 73 | ], 74 | [ 75 | InlineKeyboardButton("Updates Channel", url=UPDATE_CHANNEL_URL) 76 | ] 77 | ] 78 | ) 79 | 80 | await app.send_message( 81 | OWNER_ID, 82 | error_message, 83 | parse_mode=ParseMode.MARKDOWN, 84 | disable_web_page_preview=True, 85 | reply_markup=keyboard 86 | ) 87 | 88 | def get_user_name(from_user): 89 | if from_user: 90 | user_name = from_user.first_name 91 | if not user_name and from_user.username: 92 | user_name = f"@{from_user.username}" 93 | elif not user_name: 94 | user_name = "Anonymous" 95 | if from_user.last_name: 96 | user_name += f" {from_user.last_name}" 97 | return user_name 98 | return "Anonymous" 99 | 100 | @app.on_message(filters.chat(CHANNEL_ID) & filters.create(lambda _, __, m: m.from_user is not None)) 101 | async def handle_new_message(client: Client, message: Message): 102 | try: 103 | chat_member = await client.get_chat_member(CHANNEL_ID, message.from_user.id) 104 | if not chat_member.privileges and chat_member.status != "creator": 105 | return 106 | 107 | user_id = message.from_user.id 108 | user_name = get_user_name(message.from_user) 109 | 110 | event_date = message.date.astimezone(datetime.timezone(datetime.timedelta(hours=6))) 111 | 112 | await send_notification( 113 | event_description="Posted new message (admin)", 114 | user_name=user_name, 115 | user_id=user_id, 116 | channel_id=CHANNEL_ID, 117 | event_date=event_date 118 | ) 119 | except Exception as e: 120 | error_msg = f"**❌ Error processing admin message in channel `{CHANNEL_ID}`: {str(e)}**" 121 | print(error_msg) 122 | await client.send_message( 123 | OWNER_ID, 124 | error_msg, 125 | parse_mode=ParseMode.MARKDOWN, 126 | disable_web_page_preview=True 127 | ) 128 | 129 | @app.on_message(filters.chat(CHANNEL_ID)) 130 | async def handle_new_post(client: Client, message: Message): 131 | try: 132 | user_name = "Anonymous" 133 | user_id = "N/A" 134 | 135 | if message.from_user: 136 | user_id = message.from_user.id 137 | user_name = get_user_name(message.from_user) 138 | elif message.sender_chat: 139 | user_name = message.sender_chat.title or "Channel" 140 | user_id = message.sender_chat.id 141 | 142 | event_date = message.date.astimezone(datetime.timezone(datetime.timedelta(hours=6))) 143 | 144 | await send_notification( 145 | event_description="Posted new message", 146 | user_name=user_name, 147 | user_id=user_id, 148 | channel_id=CHANNEL_ID, 149 | event_date=event_date 150 | ) 151 | 152 | print(f"New message detected in channel {CHANNEL_ID}: {message.text or 'No text'}") 153 | except Exception as e: 154 | error_msg = f"**❌ Error processing new post in channel `{CHANNEL_ID}`: {str(e)}**" 155 | print(error_msg) 156 | await client.send_message( 157 | OWNER_ID, 158 | error_msg, 159 | parse_mode=ParseMode.MARKDOWN, 160 | disable_web_page_preview=True 161 | ) 162 | 163 | async def main(): 164 | while not (app.is_connected and user.is_connected): 165 | try: 166 | await asyncio.sleep(0.5) 167 | await app.get_me() 168 | await user.get_me() 169 | except Exception: 170 | continue 171 | 172 | print("Bot and user clients started...") 173 | 174 | try: 175 | channel = await user.get_chat(CHANNEL_ID) 176 | channel_id = channel.id 177 | print(f"Monitoring channel: {channel.title} ({CHANNEL_ID})") 178 | except Exception as e: 179 | error_msg = f"**❌ Sorry Channel Invalid `{CHANNEL_ID}`: {str(e)}**" 180 | print(error_msg) 181 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 182 | return 183 | 184 | try: 185 | chat_member = await user.get_chat_member(CHANNEL_ID, "me") 186 | if not chat_member.privileges or not chat_member.privileges.can_manage_chat: 187 | error_msg = f"**❌ User Client Don't Have Enough Permission Bro `{CHANNEL_ID}`**" 188 | print(error_msg) 189 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 190 | return 191 | except ChatAdminRequired: 192 | error_msg = f"**❌ User Client Not Admin In Base Channel `{CHANNEL_ID}`**" 193 | print(error_msg) 194 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 195 | return 196 | except Exception as e: 197 | error_msg = f"**❌ Can Not Verify User's ChatMemberStatus In `{CHANNEL_ID}`: {str(e)}**" 198 | print(error_msg) 199 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 200 | return 201 | 202 | try: 203 | bot_member = await app.get_chat_member(CHANNEL_ID, (await app.get_me()).id) 204 | if not bot_member.privileges or not bot_member.privileges.can_manage_chat: 205 | error_msg = f"**❌ Bot Client Does Not Have Proper Permission In `{CHANNEL_ID}`**" 206 | print(error_msg) 207 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 208 | return 209 | except ChatAdminRequired: 210 | error_msg = f"**❌ Bot Client Not Admin In `{CHANNEL_ID}`**" 211 | print(error_msg) 212 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 213 | return 214 | except Exception as e: 215 | error_msg = f"**❌ Can Not Verify Bot Client ChatMemberStatus In `{CHANNEL_ID}`: {str(e)}**" 216 | print(error_msg) 217 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 218 | return 219 | 220 | try: 221 | admin_log = await user.invoke( 222 | GetAdminLog( 223 | channel=await user.resolve_peer(channel_id), 224 | q="", 225 | events_filter=ChannelAdminLogEventsFilter(), 226 | admins=None, 227 | max_id=0, # Fixed from max_idouples 228 | min_id=0, 229 | limit=1 230 | ) 231 | ) 232 | except ChatAdminRequired: 233 | error_msg = f"**❌ User Client Disallowed To View Logs `{CHANNEL_ID}`**" 234 | print(error_msg) 235 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 236 | return 237 | except Exception as e: 238 | error_msg = f"**❌ User Client Failed To Retrieve Logs From `{CHANNEL_ID}`: {str(e)}**" 239 | print(error_msg) 240 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 241 | return 242 | 243 | now = datetime.datetime.now().astimezone(datetime.timezone(datetime.timedelta(hours=6))) 244 | startup_msg = f"**Smart Monitor Is Alive & Start Monitoring `{channel.title}`**" 245 | await app.send_message( 246 | OWNER_ID, 247 | startup_msg, 248 | parse_mode=ParseMode.MARKDOWN, 249 | disable_web_page_preview=True 250 | ) 251 | 252 | last_event_id = 0 253 | forty_eight_hours_ago = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=48) 254 | try: 255 | event_filter = ChannelAdminLogEventsFilter( 256 | join=True, 257 | leave=True, 258 | invite=True, 259 | ban=True, 260 | unban=True, 261 | kick=True, 262 | unkick=True, 263 | promote=True, 264 | demote=True, 265 | info=True, 266 | settings=True, 267 | pinned=True, 268 | edit=True, 269 | delete=True, 270 | group_call=True, 271 | invites=True, 272 | send=True, 273 | forums=True, 274 | sub_extend=True 275 | ) 276 | admin_log = await user.invoke( 277 | GetAdminLog( 278 | channel=await user.resolve_peer(channel_id), 279 | q="", 280 | events_filter=event_filter, 281 | admins=None, 282 | max_id=0, 283 | min_id=0, 284 | limit=100 285 | ) 286 | ) 287 | 288 | for event in reversed(admin_log.events): 289 | event_date = datetime.datetime.fromtimestamp(event.date, tz=datetime.timezone.utc) 290 | if event_date >= forty_eight_hours_ago: 291 | last_event_id = max(last_event_id, event.id) 292 | 293 | user_id = getattr(event.user_id, 'user_id', None) or event.user_id 294 | try: 295 | event_user = await user.get_users(user_id) 296 | user_name = get_user_name(event_user) 297 | except Exception as e: 298 | user_name = "Anonymous" 299 | print(f"Error fetching admin log user {user_id}: {str(e)}") 300 | 301 | event_type = type(event.action).__name__ 302 | event_description = EVENT_TYPE_MAP.get(event_type, event_type) 303 | 304 | event_date = event_date.astimezone(datetime.timezone(datetime.timedelta(hours=6))) 305 | 306 | await send_notification( 307 | event_description=event_description, 308 | user_name=user_name, 309 | user_id=user_id, 310 | channel_id=channel_id, 311 | event_date=event_date 312 | ) 313 | except Exception as e: 314 | error_msg = f"**❌ Sorry Bro Last 48 Hours Logs Not Available `{CHANNEL_ID}`: {str(e)}**" 315 | print(error_msg) 316 | await app.send_message(OWNER_ID, error_msg, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True) 317 | 318 | while True: 319 | try: 320 | event_filter = ChannelAdminLogEventsFilter( 321 | join=True, 322 | leave=True, 323 | invite=True, 324 | ban=True, 325 | unban=True, 326 | kick=True, 327 | unkick=True, 328 | promote=True, 329 | demote=True, 330 | info=True, 331 | settings=True, 332 | pinned=True, 333 | edit=True, 334 | delete=True, 335 | group_call=True, 336 | invites=True, 337 | send=True, 338 | forums=True, 339 | sub_extend=True 340 | ) 341 | admin_log = await user.invoke( 342 | GetAdminLog( 343 | channel=await user.resolve_peer(channel_id), 344 | q="", 345 | events_filter=event_filter, 346 | admins=None, 347 | max_id=0, 348 | min_id=last_event_id, 349 | limit=100 350 | ) 351 | ) 352 | 353 | for event in reversed(admin_log.events): 354 | if event.id > last_event_id: 355 | last_event_id = event.id 356 | 357 | user_id = getattr(event.user_id, 'user_id', None) or event.user_id 358 | try: 359 | event_user = await user.get_users(user_id) 360 | user_name = get_user_name(event_user) 361 | except Exception as e: 362 | user_name = "Anonymous" 363 | print(f"Error fetching admin log user {user_id}: {str(e)}") 364 | 365 | event_type = type(event.action).__name__ 366 | event_description = EVENT_TYPE_MAP.get(event_type, event_type) 367 | 368 | event_date = datetime.datetime.fromtimestamp(event.date).astimezone( 369 | datetime.timezone(datetime.timedelta(hours=6)) 370 | ) 371 | 372 | await send_notification( 373 | event_description=event_description, 374 | user_name=user_name, 375 | user_id=user_id, 376 | channel_id=channel_id, 377 | event_date=event_date 378 | ) 379 | 380 | await asyncio.sleep(30) 381 | 382 | except FloodWait as e: 383 | print(f"FloodWait: Sleeping for {e.value} seconds") 384 | await asyncio.sleep(e.value) 385 | except Exception as e: 386 | error_msg = f"**❌ Bot Client Can Not Monitor `{CHANNEL_ID}`: {str(e)}**" 387 | print(error_msg) 388 | await app.send_message( 389 | OWNER_ID, 390 | error_msg, 391 | parse_mode=ParseMode.MARKDOWN, 392 | disable_web_page_preview=True 393 | ) 394 | await asyncio.sleep(60) 395 | 396 | app.loop.create_task(main()) --------------------------------------------------------------------------------