├── runtime.txt ├── Procfile ├── cookies └── SecureXTools.txt ├── assets └── wlc.jpg ├── start.sh ├── heroku.yml ├── callback ├── __init__.py └── misc.py ├── requirements.txt ├── core ├── __init__.py ├── mongo.py ├── database.py └── start.py ├── docker-compose.yml ├── utils ├── __init__.py ├── logging_setup.py ├── dc_locations.py ├── pgbar.py └── nfy.py ├── app.py ├── Dockerfile ├── main.py ├── sample.env ├── sudoers ├── __init__.py ├── set │ └── set.py ├── speedtest │ └── speedtest.py ├── restart │ └── restart.py ├── gban │ └── gban.py ├── sudo │ └── sudo.py ├── logs │ └── logs.py ├── settings │ └── settings.py └── admin │ └── admin.py ├── cmds.txt ├── modules ├── __init__.py ├── privxutils │ └── privacy.py ├── netxutils │ ├── ip.py │ └── px.py ├── webxutils │ └── ss.py ├── dlxutils │ ├── tik.py │ ├── pin.py │ ├── fb.py │ ├── insta.py │ └── spfy.py ├── hlpxutils │ └── help.py └── infoxutils │ └── info.py ├── LICENSE ├── app.json ├── config.py └── README.md /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.13 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: bash start.sh -------------------------------------------------------------------------------- /cookies/SecureXTools.txt: -------------------------------------------------------------------------------- 1 | # Netscape HTTP Cookie File 2 | -------------------------------------------------------------------------------- /assets/wlc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSmartDevs/SecureXTools/main/assets/wlc.jpg -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | #!/bin/bash 4 | python3 main.py -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | web: Dockerfile 4 | 5 | run: 6 | worker: python3 main.py -------------------------------------------------------------------------------- /callback/__init__.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from .misc import handle_callback_query -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrogram 2 | tgcrypto 3 | aiohttp 4 | requests 5 | asyncio 6 | telegraph 7 | pillow 8 | yt-dlp 9 | python-dateutil 10 | pymongo 11 | aiofiles 12 | python-dotenv 13 | moviepy -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from .mongo import user_activity_collection 5 | from .database import auth_admins, banned_users 6 | from .start import setup_start_handler -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | smarttoolbot: 3 | build: . 4 | container_name: securextools 5 | ports: 6 | - "8000:8000" 7 | env_file: 8 | - .env 9 | volumes: 10 | - .:/app -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from .logging_setup import LOGGER 5 | from .dc_locations import get_dc_locations 6 | from .pgbar import progress_bar 7 | from .nfy import notify_admin -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from pyrogram import Client 5 | from utils import LOGGER 6 | from config import API_ID, API_HASH, BOT_TOKEN 7 | 8 | LOGGER.info("Creating Bot Client From BOT_TOKEN") 9 | 10 | app = Client( 11 | "SecureXTools", 12 | api_id=API_ID, 13 | api_hash=API_HASH, 14 | bot_token=BOT_TOKEN, 15 | workers=1000 16 | ) 17 | 18 | LOGGER.info("Bot Client Created Successfully!") -------------------------------------------------------------------------------- /core/mongo.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from pymongo import MongoClient 5 | from utils import LOGGER 6 | from config import MONGO_URL 7 | 8 | # Initialize MongoDB Client 9 | LOGGER.info("Creating MONGO_CLIENT From MONGO_URL") 10 | try: 11 | MONGO_CLIENT = MongoClient(MONGO_URL) 12 | LOGGER.info("MONGO_CLIENT Successfully Created!") 13 | except Exception as e: 14 | LOGGER.error(f"Failed to create MONGO_CLIENT: {e}") 15 | raise 16 | 17 | # Access the database and collections 18 | db = MONGO_CLIENT["user_activity_db"] 19 | user_activity_collection = db["user_activity"] -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | # Use an official Python image 4 | FROM python:3.9-slim-buster 5 | 6 | # Install system dependencies 7 | RUN apt update && apt install -y git curl ffmpeg && apt clean 8 | 9 | # Set working directory 10 | WORKDIR /app 11 | 12 | # Copy requirements and install them 13 | COPY requirements.txt . 14 | RUN pip install --no-cache-dir -r requirements.txt 15 | 16 | # Copy rest of the bot files 17 | COPY . . 18 | 19 | # Make start.sh executable 20 | RUN chmod +x start.sh 21 | 22 | # Expose port for Flask 23 | EXPOSE 8000 24 | 25 | # Run the bot and Flask server 26 | CMD ["bash", "start.sh"] -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from app import app 5 | from utils import LOGGER 6 | from core import setup_start_handler 7 | from modules import setup_modules_handlers 8 | from sudoers import setup_sudoers_handlers 9 | from callback import handle_callback_query 10 | from pyrogram import filters 11 | 12 | setup_start_handler(app) 13 | setup_modules_handlers(app) 14 | setup_sudoers_handlers(app) 15 | 16 | @app.on_callback_query() 17 | async def handle_callback(client, callback_query): 18 | await handle_callback_query(client, callback_query) 19 | 20 | if __name__ == "__main__": 21 | LOGGER.info("SecureXTools Successfully Started!🔥") 22 | app.run() -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | # Telegram API credentials (required) 5 | API_ID=YOUR_API_ID 6 | API_HASH=YOUR_API_HASH 7 | BOT_TOKEN=YOUR_BOT_TOKEN 8 | BOT_USERNAME=YOUR_BOT_USERNAME WITH @ 9 | BOT_NAME=YOUR_BOT_NAME 10 | 11 | # Admin and owner IDs (required) 12 | OWNER_ID=7303810912 13 | DEVELOPER_USER_ID=7303810912 14 | 15 | # Database URLs (required) 16 | MONGO_URL=YOUR_MONGO_URL 17 | DATABASE_URL=YOUR_DATABASE_URL 18 | 19 | # Bot settings 20 | UPDATE_CHANNEL_URL=t.me/TheSmartDevs 21 | COMMAND_PREFIX=!|.|#|,|/ 22 | MAX_VIDEO_SIZE=2147483648 23 | YT_COOKIES_PATH=./cookies/SecureXTools.txt 24 | VIDEO_RESOLUTION=1280x720 25 | 26 | # Proxy checker setting 27 | PROXY_CHECK_LIMIT=20 -------------------------------------------------------------------------------- /sudoers/__init__.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from .admin.admin import setup_admin_handler 5 | from .logs.logs import setup_logs_handler 6 | from .restart.restart import setup_restart_handler 7 | from .sudo.sudo import setup_sudo_handler 8 | from .speedtest.speedtest import setup_speed_handler 9 | from .settings.settings import setup_settings_handler 10 | from .gban.gban import setup_gban_handler 11 | from .set.set import setup_set_commands_handler 12 | 13 | def setup_sudoers_handlers(app): 14 | setup_admin_handler(app) 15 | setup_logs_handler(app) 16 | setup_restart_handler(app) 17 | setup_sudo_handler(app) 18 | setup_speed_handler(app) 19 | setup_settings_handler(app) 20 | setup_gban_handler(app) 21 | setup_set_commands_handler(app) -------------------------------------------------------------------------------- /utils/logging_setup.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | import logging 5 | from logging.handlers import RotatingFileHandler 6 | 7 | logging.basicConfig( 8 | level=logging.INFO, 9 | format="%(asctime)s - %(levelname)s - %(message)s", 10 | datefmt='%Y-%m-%d %H:%M:%S', 11 | handlers=[ 12 | RotatingFileHandler( 13 | "botlog.txt", 14 | maxBytes=50000000, 15 | backupCount=10 16 | ), 17 | logging.StreamHandler() 18 | ] 19 | ) 20 | 21 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 22 | logging.getLogger("telethon").setLevel(logging.ERROR) 23 | logging.getLogger("aiohttp").setLevel(logging.ERROR) 24 | logging.getLogger("apscheduler").setLevel(logging.ERROR) 25 | 26 | LOGGER = logging.getLogger(__name__) -------------------------------------------------------------------------------- /utils/dc_locations.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | def get_dc_locations(): 5 | """Returns a dictionary mapping Data Center IDs to their locations""" 6 | return { 7 | 1: "MIA, Miami, USA, US", 8 | 2: "AMS, Amsterdam, Netherlands, NL", 9 | 3: "MBA, Mumbai, India, IN", 10 | 4: "STO, Stockholm, Sweden, SE", 11 | 5: "SIN, Singapore, SG", 12 | 6: "LHR, London, United Kingdom, GB", 13 | 7: "FRA, Frankfurt, Germany, DE", 14 | 8: "JFK, New York, USA, US", 15 | 9: "HKG, Hong Kong, HK", 16 | 10: "TYO, Tokyo, Japan, JP", 17 | 11: "SYD, Sydney, Australia, AU", 18 | 12: "GRU, São Paulo, Brazil, BR", 19 | 13: "DXB, Dubai, UAE, AE", 20 | 14: "CDG, Paris, France, FR", 21 | 15: "ICN, Seoul, South Korea, KR", 22 | } -------------------------------------------------------------------------------- /cmds.txt: -------------------------------------------------------------------------------- 1 | start - Start SecureXTools Bot 2 | help - Get Help Menu & Commands 3 | info - Get User Info From Database 4 | id- Get Group Or Channel Info 5 | ip - Get Any Ip Information 6 | px - Check Proxy Any Type 7 | ss - Get SS Of Any Website 8 | fb - Download Facebook Video 9 | in - Download Insta Reel & Posts 10 | sp - Download Spotify Track 11 | song - Download Yt Music 12 | video - Download Yt Video 13 | tt- Download TikTok Video 14 | pnt - Download Pinterest Video 15 | settings - Change Bot All Vars [Admin] 16 | auth - Promote Sudo User [Admin] 17 | unauth - Demote Sudo User [Admin] 18 | gban - Ban User From Using Bot [Admin] 19 | gunban - Unban User From Using Bot [Admin] 20 | logs - Get Bot's Logs From Console [Admin] 21 | restart - Restart Bot And Freshly Start [Admin] 22 | speedtest - Get Bot Server Speed [Admin] 23 | send - Send Brodcast [Admin] 24 | stats - Get Statistics [Admin] -------------------------------------------------------------------------------- /core/database.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | from pymongo import MongoClient 5 | from config import DATABASE_URL 6 | from utils import LOGGER 7 | 8 | # Log the initialization attempt 9 | LOGGER.info("Creating Database Client From DATABASE_URL") 10 | 11 | try: 12 | # Create MongoDB client using DATABASE_URL from config.py 13 | mongo_client = MongoClient(DATABASE_URL) 14 | # Access the "ItsSmartTool" database 15 | db = mongo_client["ItsSmartTool"] 16 | # Access the "auth_admins" collection for authorized admins 17 | auth_admins = db["auth_admins"] 18 | # Access the "banned_users" collection for banned users 19 | banned_users = db["banned_users"] 20 | LOGGER.info("Database Client Successfully Created!") 21 | except Exception as e: 22 | # Log the error with details and raise it to halt execution 23 | LOGGER.error(f"Database Client Create Error: {e}") 24 | raise -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from .dlxutils.fb import setup_fb_handlers 5 | from .dlxutils.insta import setup_insta_handlers 6 | from .dlxutils.pin import setup_pinterest_handler 7 | from .dlxutils.spfy import setup_spotify_handler 8 | from .dlxutils.tik import setup_tt_handler 9 | from .dlxutils.yt import setup_yt_handler 10 | from .hlpxutils.help import setup_help_handler 11 | from .infoxutils.info import setup_info_handler 12 | from .netxutils.ip import setup_ip_handlers 13 | from .netxutils.px import setup_px_handler 14 | from .privxutils.privacy import setup_privacy_handler 15 | from .webxutils.ss import setup_ss_handler 16 | 17 | def setup_modules_handlers(app): 18 | setup_fb_handlers(app) 19 | setup_insta_handlers(app) 20 | setup_pinterest_handler(app) 21 | setup_spotify_handler(app) 22 | setup_tt_handler(app) 23 | setup_yt_handler(app) 24 | setup_help_handler(app) 25 | setup_info_handler(app) 26 | setup_ip_handlers(app) 27 | setup_px_handler(app) 28 | setup_privacy_handler(app) 29 | setup_ss_handler(app) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 ISmartDevs 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. -------------------------------------------------------------------------------- /utils/pgbar.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | import logging 5 | import time 6 | 7 | logging.basicConfig( 8 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', 9 | level=logging.INFO 10 | ) 11 | logger = logging.getLogger(__name__) 12 | 13 | async def progress_bar(current, total, status_message, start_time, last_update_time): 14 | """ 15 | Display a progress bar for uploads. 16 | """ 17 | elapsed_time = time.time() - start_time 18 | percentage = (current / total) * 100 19 | progress = "▓" * int(percentage // 5) + "░" * (20 - int(percentage // 5)) 20 | speed = current / elapsed_time / 1024 / 1024 21 | uploaded = current / 1024 / 1024 22 | total_size = total / 1024 / 1024 23 | 24 | if time.time() - last_update_time[0] < 1: 25 | return 26 | last_update_time[0] = time.time() 27 | 28 | text = ( 29 | f"📥 Upload Progress 📥\n\n" 30 | f"{progress}\n\n" 31 | f"🚧 Percentage: {percentage:.2f}%\n" 32 | f"⚡️ Speed: {speed:.2f} MB/s\n" 33 | f"📶 Uploaded: {uploaded:.2f} MB of {total_size:.2f} MB" 34 | ) 35 | try: 36 | await status_message.edit(text) 37 | except Exception as e: 38 | logger.error(f"Error updating progress: {e}") -------------------------------------------------------------------------------- /utils/nfy.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | import logging 5 | from pyrogram import Client 6 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton 7 | from config import OWNER_ID, DEVELOPER_USER_ID 8 | 9 | async def notify_admin(client: Client, command: str, error: Exception, message: Message): 10 | try: 11 | user = message.from_user 12 | user_fullname = f"{user.first_name} {user.last_name or ''}".strip() 13 | user_id = user.id 14 | error_message = ( 15 | "**✘ Hey Sir, New Bug Found ↯**\n\n" 16 | f"**✘ Command: `{command}` ↯**\n" 17 | f"**✘ Issue: `{str(error)}` ↯**\n" 18 | f"**✘ User: `{user_fullname}` (ID: {user_id}) ↯**\n" 19 | f"**✘ Chat ID: `{message.chat.id}` ↯**\n" 20 | f"**✘ Time: `{message.date.strftime('%Y-%m-%d %H:%M:%S')}` ↯**" 21 | ) 22 | keyboard = InlineKeyboardMarkup( 23 | [ 24 | [InlineKeyboardButton("✘ Dev ↯", user_id=DEVELOPER_USER_ID)] 25 | ] 26 | ) 27 | try: 28 | await client.send_message( 29 | chat_id=OWNER_ID, 30 | text=error_message, 31 | reply_markup=keyboard 32 | ) 33 | except Exception as admin_error: 34 | logging.error(f"Failed to notify admin {OWNER_ID}: {admin_error}") 35 | except Exception as e: 36 | logging.error(f"Error in notify_admin: {e}") 37 | -------------------------------------------------------------------------------- /core/start.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from pyrogram import filters 5 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 6 | from config import BOT_USERNAME, OWNER_ID, UPDATE_CHANNEL_URL, COMMAND_PREFIX, BOT_NAME 7 | from utils import LOGGER 8 | 9 | def setup_start_handler(app): 10 | @app.on_message(filters.command(["start"], prefixes=COMMAND_PREFIX) & filters.private) 11 | async def start_command(client, message): 12 | LOGGER.info(f"Received /start command from user {message.from_user.id}") 13 | 14 | user = message.from_user 15 | full_name = (user.first_name or "") + (f" {user.last_name}" if user.last_name else "") 16 | full_name = full_name.strip() or "User" 17 | user_mention = f"[{full_name}](tg://user?id={user.id})" 18 | 19 | welcome_text = ( 20 | f"**◑ ʜᴇʏ {user_mention}, ᴡᴇʟᴄᴏᴍᴇ ᴛᴏ ᴛʜᴇ ʙᴏᴛ**\n" 21 | f"**➻ ᴛʜɪs ɪs [{BOT_NAME}](t.me/{BOT_USERNAME.lstrip('@')}), ᴀ ғᴀsᴛ & ᴘᴏᴡᴇʀғᴜʟ ᴛᴏᴏʟᴋɪᴛ.**\n" 22 | "**━━━━━━━━━━━━━━━━━━━━━━**\n" 23 | "**Tᴏᴏʟs:** ᴛᴇʟᴇɢʀᴀᴍ ᴜsᴇʀ ɪɴғᴏ ᴄʜᴇᴄᴋᴇʀ, ɪᴘ ᴄʜᴇᴄᴋᴇʀ, ᴘʀᴏxʏ ᴄʜᴇᴄᴋᴇʀ, sᴄʀᴇᴇɴsʜᴏᴛ.\n\n" 24 | "**ᴅᴏᴡɴʟᴏᴀᴅ ᴘʟᴀᴛғᴏʀᴍs:** ʏᴏᴜᴛᴜʙᴇ, ғᴀᴄᴇʙᴏᴏᴋ, ɪɴsᴛᴀɢʀᴀᴍ, ᴘɪɴᴛᴇʀᴇsᴛ, sᴘᴏᴛɪғʏ, ᴛɪᴋᴛᴏᴋ." 25 | ) 26 | 27 | buttons = InlineKeyboardMarkup( 28 | [ 29 | [InlineKeyboardButton("➕ Add Me", url=f"https://t.me/{BOT_USERNAME.lstrip('@')}?startgroup=true")], 30 | [ 31 | InlineKeyboardButton("🔧 Developer", user_id=OWNER_ID), 32 | InlineKeyboardButton("✍🏻 Support", url=UPDATE_CHANNEL_URL) 33 | ], 34 | [InlineKeyboardButton("ℹ️ Help & Command", callback_data="helpmenu")] 35 | ] 36 | ) 37 | 38 | await client.send_photo( 39 | chat_id=message.chat.id, 40 | photo="assets/wlc.jpg", 41 | caption=welcome_text, 42 | reply_markup=buttons 43 | ) 44 | LOGGER.info(f"Sent welcome message to user {message.from_user.id}") -------------------------------------------------------------------------------- /sudoers/set/set.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from pyrogram import filters 5 | from pyrogram.types import BotCommand 6 | from pyrogram.enums import ParseMode 7 | from config import OWNER_ID 8 | from utils import LOGGER 9 | 10 | BOT_COMMANDS = [ 11 | BotCommand("start", "みStart SecureXTools Bot↯"), 12 | BotCommand("help", "みGet Help Menu & Commands↯"), 13 | BotCommand("info", "みGet User Info From Database↯"), 14 | BotCommand("id", "みGet Group Or Channel Info↯"), 15 | BotCommand("ip", "みGet Any Ip Information↯"), 16 | BotCommand("px", "みCheck Proxy Any Type↯"), 17 | BotCommand("ss", "みGet SS Of Any Website↯"), 18 | BotCommand("fb", "みDownload Facebook Video↯"), 19 | BotCommand("in", "みDownload Insta Reel & Posts↯"), 20 | BotCommand("sp", "みDownload Spotify Track↯"), 21 | BotCommand("song", "みDownload Yt Music↯"), 22 | BotCommand("video", "みDownload Yt Video↯"), 23 | BotCommand("tt", "みDownload TikTok Video↯"), 24 | BotCommand("pnt", "みDownload Pinterest Video↯"), 25 | BotCommand("settings", "みChange Bot All Vars [Admin]↯"), 26 | BotCommand("auth", "みPromote Sudo User [Admin]↯"), 27 | BotCommand("unauth", "みDemote Sudo User [Admin]↯"), 28 | BotCommand("gban", "みBan User From Using Bot [Admin]↯"), 29 | BotCommand("gunban", "みUnban User From Using Bot [Admin]↯"), 30 | BotCommand("logs", "みGet Bot's Logs From Console [Admin]↯"), 31 | BotCommand("restart", "みRestart Bot And Freshly Start [Admin]↯"), 32 | BotCommand("speedtest", "みGet Bot Server Speed [Admin]↯"), 33 | BotCommand("send", "みSend Brodcast [Admin]↯"), 34 | BotCommand("stats", "みGet Statistics [Admin]↯"), 35 | ] 36 | 37 | def setup_set_commands_handler(app): 38 | @app.on_message(filters.command("set") & filters.user(OWNER_ID)) 39 | async def set_commands(client, message): 40 | await client.set_bot_commands(BOT_COMMANDS) 41 | await client.send_message( 42 | chat_id=message.chat.id, 43 | text="み ¡**BotFather Commands Successfully Set**↯", 44 | parse_mode=ParseMode.MARKDOWN 45 | ) 46 | LOGGER.info(f"BotFather commands set by owner {message.from_user.id}") -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SecureXTools", 3 | "description": "A fast and powerful Telegram bot with tools for user info, IP checking, proxy checking, screenshots, and media downloads from YouTube, Facebook, Instagram, Pinterest, Spotify, and TikTok.", 4 | "repository": "https://github.com/TheSmartDevs/SecureXTools", 5 | "keywords": ["telegram", "bot", "pyrogram", "python"], 6 | "env": { 7 | "API_ID": { 8 | "description": "Telegram API ID obtained from https://my.telegram.org", 9 | "required": true 10 | }, 11 | "API_HASH": { 12 | "description": "Telegram API Hash obtained from https://my.telegram.org", 13 | "required": true 14 | }, 15 | "BOT_TOKEN": { 16 | "description": "Bot Token obtained from @BotFather on Telegram", 17 | "required": true 18 | }, 19 | "BOT_USERNAME": { 20 | "description": "Bot Username (e.g., @SecureXToolsBot)", 21 | "required": true 22 | }, 23 | "BOT_NAME": { 24 | "description": "Bot Name (e.g., SecureXToolsBot)", 25 | "required": true 26 | }, 27 | "OWNER_ID": { 28 | "description": "Telegram User ID of the bot owner", 29 | "required": true 30 | }, 31 | "MONGO_URL": { 32 | "description": "MongoDB connection URL (e.g., mongodb://localhost:27017/securextools)", 33 | "required": true 34 | }, 35 | "UPDATE_CHANNEL_URL": { 36 | "description": "URL of the Telegram channel for updates and support", 37 | "value": "t.me/TheSmartDev" 38 | }, 39 | "COMMAND_PREFIX": { 40 | "description": "Command prefixes for bot commands (e.g., !, ., #, ,, /)", 41 | "value": "!|.|#|,|/" 42 | }, 43 | "MAX_VIDEO_SIZE": { 44 | "description": "Maximum video file size in bytes", 45 | "value": "2147483648" 46 | }, 47 | "YT_COOKIES_PATH": { 48 | "description": "Path to YouTube cookies file", 49 | "value": "./cookies/ItsSmartToolBot.txt" 50 | }, 51 | "VIDEO_RESOLUTION": { 52 | "description": "Video resolution for YouTube downloads (e.g., 1280x720)", 53 | "value": "1280x720" 54 | } 55 | }, 56 | "buildpacks": [ 57 | { 58 | "url": "heroku/python" 59 | } 60 | ], 61 | "formation": { 62 | "worker": { 63 | "quantity": 1, 64 | "size": "free" 65 | } 66 | }, 67 | "stack": "heroku-22", 68 | "addons": [] 69 | } -------------------------------------------------------------------------------- /modules/privxutils/privacy.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | from pyrogram import Client, filters 5 | from pyrogram.enums import ParseMode 6 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 7 | from config import COMMAND_PREFIX 8 | from utils import LOGGER # (optional, for logging consistency) 9 | from core import banned_users 10 | 11 | # Define your privacy policy text 12 | PRIVACY_POLICY = """ 13 | 📜 Privacy Policy for SecureXTools 💥 14 | ━━━━━━━━━━━━━━━━━ 15 | 16 | Welcome to SecureXTools 💥. By using our services, you agree to this privacy policy. 17 | 18 | 1. Information We Collect: 19 | - Personal Information: User ID and username for personalization. 20 | - Usage Data: Information on how you use the app to improve our services. 21 | 22 | 2. Usage of Information: 23 | - Service Enhancement: To provide and improve SecureXTools. 24 | - Communication: Updates and new features. 25 | - Security: To prevent unauthorized access. 26 | - Advertisements: Display of promotions. 27 | 28 | 3. Data Security: 29 | - These tools do not store any data, ensuring your privacy. 30 | - We use strong security measures, although no system is 100% secure. 31 | 32 | Thank you for using SecureXTools 💥. We prioritize your privacy and security. 33 | """ 34 | 35 | def setup_privacy_handler(app: Client): 36 | @app.on_message(filters.command(["privacy"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 37 | async def show_privacy_policy(client, message): 38 | user_id = message.from_user.id if message.from_user else None 39 | if user_id and banned_users.find_one({"user_id": user_id}): 40 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**") 41 | return 42 | 43 | await client.send_message( 44 | message.chat.id, 45 | PRIVACY_POLICY, 46 | parse_mode=ParseMode.HTML, 47 | reply_markup=InlineKeyboardMarkup([ 48 | [InlineKeyboardButton("Close", callback_data="close_privacy_policy")] 49 | ]) 50 | ) 51 | 52 | @app.on_callback_query(filters.regex("close_privacy_policy")) 53 | async def close_privacy_policy(client, callback_query): 54 | await callback_query.message.delete() -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | # Note: Configure via .env (VPS/Heroku local), direct edits to this file (VPS), or Heroku config vars (app.json/dashboard). 5 | import os 6 | from dotenv import load_dotenv 7 | 8 | # Load .env file if it exists (for VPS or local Heroku testing), but allow Heroku config vars to take precedence 9 | load_dotenv() 10 | 11 | def get_env_or_default(key, default=None, cast_func=str): 12 | """Helper function to load environment variables with type casting and default values.""" 13 | value = os.getenv(key) 14 | if value is not None and value.strip() != "": 15 | try: 16 | return cast_func(value) 17 | except (ValueError, TypeError) as e: 18 | print(f"Error casting {key} with value '{value}' to {cast_func.__name__}: {e}") 19 | return default 20 | return default 21 | 22 | # TELEGRAM WITH PYROGRAM MTPROTO API CONNECTION AND AUTHORIZATION SETUP 23 | API_ID = get_env_or_default("API_ID", "Your_API_ID_Here") 24 | API_HASH = get_env_or_default("API_HASH", "Your_API_HASH_Here") 25 | BOT_TOKEN = get_env_or_default("BOT_TOKEN", "Your_BOT_TOKEN_Here") 26 | BOT_USERNAME = get_env_or_default("BOT_USERNAME", "@YourBotUsername") 27 | BOT_NAME = get_env_or_default("BOT_NAME", "YourBotName") 28 | 29 | # ADMINS AND SUDO USERS FOR BROADCAST AND OTHER SUDO WORKS 30 | OWNER_ID = get_env_or_default("OWNER_ID", "Your_OWNER_ID_Here", int) 31 | DEVELOPER_USER_ID = get_env_or_default("DEVELOPER_USER_ID", "Your_OWNER_ID_Here", int) 32 | 33 | # MONGODB URL AND DATABASE URL FOR USER DATABASE AND GROUP SETTINGS DATABASE 34 | MONGO_URL = get_env_or_default("MONGO_URL", "Your_MONGO_URL_Here") 35 | DATABASE_URL = get_env_or_default("DATABASE_URL", "Your_MONGO_URL_Here") 36 | 37 | # ALL COMMANDS PREFIXES FOR ALLOWING ALL COMMANDS SUPPORT 38 | raw_prefixes = get_env_or_default("COMMAND_PREFIX", "!|.|#|,|/") 39 | COMMAND_PREFIX = [prefix.strip() for prefix in raw_prefixes.split("|") if prefix.strip()] 40 | 41 | # BOT DEVS CHANNEL URL AND PROFILE ERROR URL 42 | UPDATE_CHANNEL_URL = get_env_or_default("UPDATE_CHANNEL_URL", "t.me/TheSmartDev") 43 | 44 | # MAX FILE SIZE LIMITS FOR OCR TOOLS AND IMGAI 45 | IMGAI_SIZE_LIMIT = get_env_or_default("IMGAI_SIZE_LIMIT", 5242880, int) 46 | MAX_TXT_SIZE = get_env_or_default("MAX_TXT_SIZE", 15728640, int) 47 | MAX_VIDEO_SIZE = get_env_or_default("MAX_VIDEO_SIZE", 2147483648, int) 48 | 49 | # YOUTUBE COOKIES PATH 50 | YT_COOKIES_PATH = get_env_or_default("YT_COOKIES_PATH", "./cookies/ItsSmartToolBot.txt") 51 | 52 | # VIDEO RESOLUTION FOR YOUTUBE DOWNLOADS 53 | VIDEO_RESOLUTION = get_env_or_default("VIDEO_RESOLUTION", "1280x720", lambda x: tuple(map(int, x.split('x')))) 54 | 55 | # PROXY CHECK LIMIT 56 | PROXY_CHECK_LIMIT = get_env_or_default("PROXY_CHECK_LIMIT", 20, int) 57 | 58 | # Validation for critical variables 59 | required_vars = { 60 | "API_ID": API_ID, 61 | "API_HASH": API_HASH, 62 | "BOT_TOKEN": BOT_TOKEN, 63 | "BOT_USERNAME": BOT_USERNAME, 64 | "OWNER_ID": OWNER_ID, 65 | "DEVELOPER_USER_ID": DEVELOPER_USER_ID, 66 | "MONGO_URL": MONGO_URL 67 | } 68 | 69 | for var_name, var_value in required_vars.items(): 70 | if var_value is None or var_value == f"Your_{var_name}_Here" or (isinstance(var_value, str) and var_value.strip() == ""): 71 | raise ValueError(f"Required variable {var_name} is missing or invalid. Set it in .env (VPS), config.py (VPS), or Heroku config vars.") 72 | 73 | # Logging for debugging 74 | print("Loaded COMMAND_PREFIX:", COMMAND_PREFIX) 75 | 76 | if not COMMAND_PREFIX: 77 | raise ValueError("No command prefixes found. Set COMMAND_PREFIX in .env, config.py, or Heroku config vars.") -------------------------------------------------------------------------------- /modules/netxutils/ip.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import aiohttp 5 | import asyncio 6 | from pyrogram import Client, filters 7 | from pyrogram.types import Message 8 | from pyrogram.enums import ParseMode 9 | from config import COMMAND_PREFIX 10 | from utils import LOGGER, notify_admin # Use LOGGER and notify_admin from utils 11 | from core import banned_users # Use banned_users from core 12 | 13 | async def get_ip_info(ip: str) -> str: 14 | url = f"https://ipinfo.io/{ip}/json" 15 | try: 16 | async with aiohttp.ClientSession() as session: 17 | async with session.get(url) as response: 18 | response.raise_for_status() 19 | data = await response.json() 20 | 21 | ip = data.get("ip", "Unknown") 22 | asn = data.get("org", "Unknown") 23 | isp = data.get("org", "Unknown") 24 | country = data.get("country", "Unknown") 25 | city = data.get("city", "Unknown") 26 | timezone = data.get("timezone", "Unknown") 27 | 28 | # Simulated IP fraud score and risk level for demonstration 29 | fraud_score = 0 30 | risk_level = "low" if fraud_score < 50 else "high" 31 | 32 | details = ( 33 | f"**YOUR IP INFORMATION 🌐**\n" 34 | f"━━━━━━━━━━━━━━━━━━\n" 35 | f"**IP:** `{ip}`\n" 36 | f"**ASN:** `{asn}`\n" 37 | f"**ISP:** `{isp}`\n" 38 | f"**Country City:** `{country} {city}`\n" 39 | f"**Timezone:** `{timezone}`\n" 40 | f"**IP Fraud Score:** `{fraud_score}`\n" 41 | f"**Risk LEVEL:** `{risk_level} Risk`\n" 42 | f"━━━━━━━━━━━━━━━━━━\n" 43 | ) 44 | 45 | return details 46 | except aiohttp.ClientError as e: 47 | LOGGER.error(f"Failed to fetch IP info for {ip}: {e}") 48 | await notify_admin(None, f"{COMMAND_PREFIX}ip", e, None) 49 | return "Invalid IP address or API error" 50 | except Exception as e: 51 | LOGGER.error(f"Unexpected error fetching IP info for {ip}: {e}") 52 | await notify_admin(None, f"{COMMAND_PREFIX}ip", e, None) 53 | return "Invalid IP address or API error" 54 | 55 | async def ip_info_handler(client: Client, message: Message): 56 | user_id = message.from_user.id if message.from_user else None 57 | if user_id and banned_users.find_one({"user_id": user_id}): 58 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**") 59 | return 60 | 61 | if len(message.command) <= 1: 62 | await client.send_message( 63 | message.chat.id, 64 | "**❌ Please provide a single IP address.**", 65 | parse_mode=ParseMode.MARKDOWN, 66 | disable_web_page_preview=True 67 | ) 68 | return 69 | 70 | ip = message.command[1] 71 | fetching_msg = await client.send_message( 72 | message.chat.id, 73 | "**Fetching IP Info Please Wait.....✨**", 74 | parse_mode=ParseMode.MARKDOWN, 75 | disable_web_page_preview=True 76 | ) 77 | 78 | try: 79 | details = await get_ip_info(ip) 80 | if details.startswith("Invalid"): 81 | raise Exception("Failed to retrieve IP information") 82 | 83 | if message.from_user: 84 | user_full_name = f"{message.from_user.first_name} {message.from_user.last_name or ''}".strip() 85 | user_info = f"\n**Ip-Info Grab By:** [{user_full_name}](tg://user?id={message.from_user.id})" 86 | else: 87 | group_name = message.chat.title or "this group" 88 | group_url = f"https://t.me/{message.chat.username}" if message.chat.username else "this group" 89 | user_info = f"\n**Ip-Info Grab By:** [{group_name}]({group_url})" 90 | 91 | details += user_info 92 | 93 | await fetching_msg.edit_text( 94 | details, 95 | parse_mode=ParseMode.MARKDOWN, 96 | disable_web_page_preview=True 97 | ) 98 | except Exception as e: 99 | LOGGER.error(f"Error processing IP info for {ip}: {e}") 100 | await notify_admin(client, f"{COMMAND_PREFIX}ip", e, message) 101 | await fetching_msg.edit_text( 102 | "**❌ Sorry Bro IP Info API Dead**", 103 | parse_mode=ParseMode.MARKDOWN, 104 | disable_web_page_preview=True 105 | ) 106 | 107 | def setup_ip_handlers(app: Client): 108 | @app.on_message(filters.command(["ip", ".ip"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 109 | async def ip_info(client: Client, message: Message): 110 | await ip_info_handler(client, message) -------------------------------------------------------------------------------- /callback/misc.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 5 | from pyrogram.enums import ParseMode, ChatType 6 | from config import BOT_USERNAME, OWNER_ID, UPDATE_CHANNEL_URL, BOT_NAME, COMMAND_PREFIX 7 | from utils import LOGGER 8 | from core import banned_users 9 | from pyrogram import filters 10 | import os 11 | 12 | def setup_help_handler(app): 13 | @app.on_message(filters.command(["help", "tutorial"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 14 | async def help_message(client, message): 15 | user_id = message.from_user.id if message.from_user else None 16 | if user_id and banned_users.find_one({"user_id": user_id}): 17 | await client.send_message(message.chat.id, "**✘ Sorry, You're Banned From Using Me!**") 18 | return 19 | 20 | user = message.from_user 21 | full_name = (user.first_name or "") + (f" {user.last_name}" if user and user.last_name else "") 22 | full_name = full_name.strip() or "User" 23 | user_mention = f"[{full_name}](tg://user?id={user.id})" if user else "User" 24 | 25 | if message.chat.type == ChatType.PRIVATE: 26 | help_text = ( 27 | f"**◑ Hey {user_mention}, Welcome to the Bot**\n" 28 | f"**➻ This is [{BOT_NAME}](t.me/{BOT_USERNAME.lstrip('@')}), a fast & powerful toolkit.**\n" 29 | "**━━━━━━━━━━━━━━━━━━━━━━**\n" 30 | "**This bot helps you manage your groups and provides various tools.**\n\n" 31 | "**Here are the available commands:**\n" 32 | "━━━━━━━━━━━━━━━━\n" 33 | "**/info** - **Get User Information.**\n" 34 | "**/id** - **Get Group & Channel Information.**\n" 35 | "**/ip** - **Get IP information.**\n" 36 | "**/px** - **Http/Https Proxy Checker.**\n" 37 | "**/ss** - **Take Screenshot of Website.**\n" 38 | "**/fb** - **Download Facebook video.**\n" 39 | "**/in** - **Download Instagram Photos, Reel Or Stories.**\n" 40 | "**/sp** - **Download Spotify Track/Album Or Playlist.**\n" 41 | "**/song** - **Download Music or Youtube as Mp3 Format.**\n" 42 | "**/video** - **Download Youtube Video.**\n" 43 | "**/tt** - **Download Tiktok Video.**\n" 44 | "**/pnt** - **Download Pinterest Video.**\n" 45 | "**━━━━━━━━━━━━━━━━━━━━━━**\n" 46 | "**Tools:** Telegram user info checker, IP checker, proxy checker, screenshot.\n\n" 47 | "**Download platforms:** YouTube, Facebook, Instagram, Pinterest, Spotify, TikTok." 48 | ) 49 | else: 50 | group_name = message.chat.title if message.chat.title else "this group" 51 | help_text = ( 52 | f"**◑ Hey {user_mention}, Welcome to {group_name}!**\n" 53 | f"**➻ This is [{BOT_NAME}](t.me/{BOT_USERNAME.lstrip('@')}), a fast & powerful toolkit.**\n" 54 | "**━━━━━━━━━━━━━━━━━━━━━━**\n" 55 | "**This bot helps you manage your groups and provides various tools.**\n\n" 56 | "**Here are the available commands:**\n" 57 | "━━━━━━━━━━━━━━━━\n" 58 | "**/info** - **Get User Information.**\n" 59 | "**/id** - **Get Group & Channel Information.**\n" 60 | "**/ip** - **Get IP information.**\n" 61 | "**/px** - **Http/Https Proxy Checker.**\n" 62 | "**/ss** - **Take Screenshot of Website.**\n" 63 | "**/fb** - **Download Facebook video.**\n" 64 | "**/in** - **Download Instagram Photos, Reel Or Stories.**\n" 65 | "**/sp** - **Download Spotify Track/Album Or Playlist.**\n" 66 | "**/song** - **Download Music or Youtube as Mp3 Format.**\n" 67 | "**/video** - **Download Youtube Video.**\n" 68 | "**/tt** - **Download Tiktok Video.**\n" 69 | "**/pnt** - **Download Pinterest Video.**\n" 70 | "**━━━━━━━━━━━━━━━━━━━━━━**\n" 71 | "**Tools:** Telegram user info checker, IP checker, proxy checker, screenshot.\n\n" 72 | "**Download platforms:** YouTube, Facebook, Instagram, Pinterest, Spotify, TikTok." 73 | ) 74 | 75 | buttons = InlineKeyboardMarkup( 76 | [ 77 | [InlineKeyboardButton("➕ Add Me", url=f"https://t.me/{BOT_USERNAME.lstrip('@')}?startgroup=true")], 78 | [ 79 | InlineKeyboardButton("🔧 Developer", user_id=OWNER_ID), 80 | InlineKeyboardButton("✍🏻 Support", url=UPDATE_CHANNEL_URL) 81 | ], 82 | [InlineKeyboardButton("ℹ️ Help & Command", callback_data="helpmenu")] 83 | ] 84 | ) 85 | 86 | # Path to the welcome image 87 | photo_path = "assets/wlc.jpg" 88 | 89 | if os.path.exists(photo_path): 90 | await client.send_photo( 91 | chat_id=message.chat.id, 92 | photo=photo_path, 93 | caption=help_text, 94 | parse_mode=ParseMode.MARKDOWN, 95 | reply_markup=buttons 96 | ) 97 | LOGGER.info(f"Sent help message with photo to chat {message.chat.id}") 98 | else: 99 | await client.send_message( 100 | chat_id=message.chat.id, 101 | text=help_text, 102 | parse_mode=ParseMode.MARKDOWN, 103 | reply_markup=buttons, 104 | disable_web_page_preview=True 105 | ) 106 | LOGGER.warning(f"Photo {photo_path} not found, sent help message without photo to chat {message.chat.id}") -------------------------------------------------------------------------------- /modules/webxutils/ss.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import requests 6 | import time 7 | import asyncio 8 | from pyrogram import Client, filters 9 | from pyrogram.types import Message 10 | from pyrogram.enums import ParseMode 11 | from config import COMMAND_PREFIX 12 | from urllib.parse import quote 13 | from utils import LOGGER, notify_admin # Import LOGGER and notify_admin from utils 14 | from core import banned_users # Import banned_users for banned user check 15 | 16 | # ScreenshotOne API endpoint 17 | SCREENSHOT_API_URL = "https://api.screenshotone.com/take" 18 | ACCESS_KEY = "Z8LQ6Z0DsTQV_A" # Your API access key 19 | MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB limit for Telegram photos 20 | 21 | def validate_url(url: str) -> bool: 22 | """Basic URL validation for user input""" 23 | return '.' in url and len(url) < 2048 24 | 25 | def normalize_url(url: str) -> str: 26 | """Add scheme if missing""" 27 | if url.startswith(('http://', 'https://')): 28 | return url 29 | else: 30 | return f"https://{url}" 31 | 32 | async def fetch_screenshot(url: str): 33 | """Fetch screenshot from ScreenshotOne API""" 34 | api_url = f"{SCREENSHOT_API_URL}?access_key={ACCESS_KEY}&url={quote(url)}&format=jpg&block_ads=true&block_cookie_banners=true&block_banners_by_heuristics=false&block_trackers=true&delay=0&timeout=60&response_type=by_format&image_quality=80" 35 | 36 | try: 37 | response = requests.get(api_url, stream=True) 38 | response.raise_for_status() 39 | 40 | # Check content type and size 41 | content_type = response.headers.get('Content-Type', '') 42 | if 'image' not in content_type: 43 | raise ValueError(f"Unexpected content type: {content_type}") 44 | 45 | # Check file size 46 | content_length = int(response.headers.get('Content-Length', 0)) 47 | if content_length > MAX_FILE_SIZE: 48 | raise ValueError(f"Screenshot too large ({content_length / 1024 / 1024:.1f}MB)") 49 | 50 | return response 51 | 52 | except requests.exceptions.RequestException as e: 53 | LOGGER.error(f"Failed to fetch screenshot: {e}") 54 | return None 55 | 56 | def setup_ss_handler(app: Client): 57 | @app.on_message(filters.command(["ss", "sshot", "screenshot", "snap"], prefixes=COMMAND_PREFIX) & 58 | (filters.private | filters.group)) 59 | async def capture_screenshot(client, message: Message): 60 | """Handle screenshot capture command""" 61 | user_id = message.from_user.id if message.from_user else None 62 | if user_id and banned_users.find_one({"user_id": user_id}): 63 | await client.send_message( 64 | chat_id=message.chat.id, 65 | text="**✘Sorry You're Banned From Using Me↯**", 66 | parse_mode=ParseMode.MARKDOWN 67 | ) 68 | return 69 | 70 | # Extract URL from the command 71 | if len(message.command) < 2: 72 | await client.send_message( 73 | chat_id=message.chat.id, 74 | text="**❌ Please provide a URL after the command**", 75 | parse_mode=ParseMode.MARKDOWN 76 | ) 77 | return 78 | 79 | url = message.command[1].strip() 80 | 81 | if not validate_url(url): 82 | await client.send_message( 83 | chat_id=message.chat.id, 84 | text="**❌ Invalid URL format**", 85 | parse_mode=ParseMode.MARKDOWN 86 | ) 87 | return 88 | 89 | processing_msg = await client.send_message( 90 | chat_id=message.chat.id, 91 | text="**Capturing ScreenShot Please Wait**", 92 | parse_mode=ParseMode.MARKDOWN 93 | ) 94 | 95 | temp_file = None 96 | try: 97 | # Normalize URL 98 | url = normalize_url(url) 99 | 100 | # Fetch screenshot from ScreenshotOne API 101 | start_time = time.time() 102 | response = await fetch_screenshot(url) 103 | 104 | if not response: 105 | raise ValueError("Failed to capture screenshot.") 106 | 107 | # Generate a unique filename 108 | timestamp = int(time.time()) 109 | temp_file = f"screenshot_{timestamp}.jpg" 110 | 111 | # Save the image 112 | with open(temp_file, 'wb') as file: 113 | for chunk in response.iter_content(chunk_size=8192): 114 | if chunk: 115 | file.write(chunk) 116 | 117 | # Verify file size before sending 118 | file_size = os.path.getsize(temp_file) 119 | if file_size > MAX_FILE_SIZE: 120 | raise ValueError(f"Resulting file too large ({file_size/1024/1024:.1f}MB)") 121 | 122 | # Send the photo without caption 123 | await client.send_photo( 124 | chat_id=message.chat.id, 125 | photo=temp_file 126 | ) 127 | 128 | # Delete loading message after successful screenshot send 129 | await client.delete_messages( 130 | chat_id=processing_msg.chat.id, 131 | message_ids=processing_msg.id 132 | ) 133 | 134 | except Exception as e: 135 | # For ANY error, edit the message to "Sorry Bro API Dead" 136 | error_msg = "**Sorry Bro SS Capture API Dead**" 137 | try: 138 | await client.edit_message_text( 139 | chat_id=processing_msg.chat.id, 140 | message_id=processing_msg.id, 141 | text=error_msg, 142 | parse_mode=ParseMode.MARKDOWN 143 | ) 144 | except Exception as edit_error: 145 | LOGGER.warning(f"Failed to edit processing message: {edit_error}") 146 | LOGGER.error(f"Error in capture_screenshot: {e}") 147 | # Notify admins of error 148 | await notify_admin(client, "/ss", e, message) 149 | finally: 150 | # Clean up in all cases 151 | if temp_file and os.path.exists(temp_file): 152 | try: 153 | os.remove(temp_file) 154 | except Exception as cleanup_error: 155 | LOGGER.warning(f"Failed to remove temp file: {cleanup_error}") -------------------------------------------------------------------------------- /sudoers/speedtest/speedtest.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import asyncio 5 | import subprocess 6 | import json 7 | from concurrent.futures import ThreadPoolExecutor 8 | from pyrogram import Client, filters 9 | from pyrogram.handlers import MessageHandler 10 | from pyrogram.enums import ParseMode, ChatType 11 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup 12 | from config import OWNER_ID, COMMAND_PREFIX, UPDATE_CHANNEL_URL 13 | from core import auth_admins 14 | from utils import LOGGER 15 | 16 | # Helper function to convert speed to human-readable format 17 | def speed_convert(size: float, is_mbps: bool = False) -> str: 18 | if is_mbps: 19 | return f"{size:.2f} Mbps" 20 | power = 2**10 21 | n = 0 22 | power_labels = {0: '', 1: 'K', 2: 'M', 3: 'G', 4: 'T'} 23 | while size > power: 24 | size /= power 25 | n += 1 26 | return f"{size:.2f} {power_labels[n]}bps" 27 | 28 | # Helper function to convert bytes to human-readable file size 29 | def get_readable_file_size(size_in_bytes: int) -> str: 30 | if size_in_bytes < 1024: 31 | return f"{size_in_bytes} B" 32 | power = 1024 33 | n = 0 34 | power_labels = {0: 'B', 1: 'KB', 2: 'MB', 3: 'GB', 4: 'TB'} 35 | while size_in_bytes >= power: 36 | size_in_bytes /= power 37 | n += 1 38 | return f"{size_in_bytes:.2f} {power_labels[n]}" 39 | 40 | # Function to perform speed test 41 | def run_speedtest(): 42 | try: 43 | # Use speedtest-cli for detailed JSON output 44 | result = subprocess.run(["speedtest-cli", "--secure", "--json"], capture_output=True, text=True) 45 | if result.returncode != 0: 46 | raise Exception("Speedtest failed.") 47 | data = json.loads(result.stdout) 48 | return data 49 | except Exception as e: 50 | LOGGER.error(f"Speedtest error: {e}") 51 | return {"error": str(e)} 52 | 53 | # Async function to handle speed test logic 54 | async def run_speedtest_task(client: Client, chat_id: int, status_message: Message): 55 | # Run speed test in background thread 56 | with ThreadPoolExecutor() as pool: 57 | try: 58 | result = await asyncio.get_running_loop().run_in_executor(pool, run_speedtest) 59 | except Exception as e: 60 | LOGGER.error(f"Error running speedtest task: {e}") 61 | await status_message.edit_text("✘ Speed Test API Dead ↯", parse_mode=ParseMode.HTML) 62 | return 63 | 64 | if "error" in result: 65 | await status_message.edit_text(f"✘ Speed Test Failed: {result['error']} ↯", parse_mode=ParseMode.HTML) 66 | return 67 | 68 | # Format the results with a stylized design using ✘, ↯, and other symbols 69 | response_text = ( 70 | "✘《 💥 SPEEDTEST RESULTS ↯ 》\n" 71 | f"↯ Upload Speed: {speed_convert(result['upload'])}\n" 72 | f"↯ Download Speed: {speed_convert(result['download'])}\n" 73 | f"↯ Ping: {result['ping']:.2f} ms\n" 74 | f"↯ Timestamp: {result['timestamp']}\n" 75 | f"↯ Data Sent: {get_readable_file_size(int(result['bytes_sent']))}\n" 76 | f"↯ Data Received: {get_readable_file_size(int(result['bytes_received']))}\n" 77 | "✘《 🌐 SERVER INFO ↯ 》\n" 78 | f"↯ Name: {result['server']['name']}\n" 79 | f"↯ Country: {result['server']['country']}, {result['server']['cc']}\n" 80 | f"↯ Sponsor: {result['server']['sponsor']}\n" 81 | f"↯ Latency: {result['server']['latency']:.2f} ms\n" 82 | f"↯ Latitude: {result['server']['lat']}\n" 83 | f"↯ Longitude: {result['server']['lon']}\n" 84 | "✘《 👾 CLIENT INFO ↯ 》\n" 85 | f"↯ IP Address: {result['client']['ip']}\n" 86 | f"↯ Latitude: {result['client']['lat']}\n" 87 | f"↯ Longitude: {result['client']['lon']}\n" 88 | f"↯ Country: {result['client']['country']}\n" 89 | f"↯ ISP: {result['client']['isp']}\n" 90 | f"↯ ISP Rating: {result['client'].get('isprating', 'N/A')}\n" 91 | "✘ Powered by @TheSmartDev ↯" 92 | ) 93 | 94 | # Create inline keyboard with Update News button 95 | keyboard = InlineKeyboardMarkup([ 96 | [InlineKeyboardButton("🔔 Update News", url=UPDATE_CHANNEL_URL)] 97 | ]) 98 | 99 | # Delete the status message 100 | await status_message.delete() 101 | 102 | # Send the final result with the inline button 103 | await client.send_message( 104 | chat_id=chat_id, 105 | text=response_text, 106 | parse_mode=ParseMode.HTML, 107 | reply_markup=keyboard 108 | ) 109 | 110 | # Handler for speed test command 111 | async def speedtest_handler(client: Client, message: Message): 112 | user_id = message.from_user.id 113 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 114 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 115 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 116 | LOGGER.info("User not admin or owner, sending restricted message") 117 | await client.send_message( 118 | chat_id=message.chat.id, 119 | text="✘ Kids Not Allowed To Do This ↯", 120 | parse_mode=ParseMode.HTML 121 | ) 122 | return 123 | 124 | # Send initial status message directly (no reply) 125 | status_message = await client.send_message( 126 | chat_id=message.chat.id, 127 | text="✘ Running Speedtest On Your Server ↯", 128 | parse_mode=ParseMode.HTML 129 | ) 130 | 131 | # Schedule the speed test task to run in the background 132 | asyncio.create_task(run_speedtest_task(client, message.chat.id, status_message)) 133 | 134 | # Setup function to add the speed test handler 135 | def setup_speed_handler(app: Client): 136 | app.add_handler(MessageHandler( 137 | speedtest_handler, 138 | filters.command("speedtest", prefixes=COMMAND_PREFIX) & (filters.private | filters.group) 139 | )) 140 | -------------------------------------------------------------------------------- /sudoers/restart/restart.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | #This Code Basically Forked From https://github.com/abirxdhackz/RestartModule 4 | 5 | import shutil 6 | import os 7 | import asyncio 8 | from pyrogram import Client, filters 9 | from pyrogram.enums import ParseMode 10 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 11 | from config import OWNER_ID, UPDATE_CHANNEL_URL, COMMAND_PREFIX 12 | from core import auth_admins 13 | from utils import LOGGER 14 | 15 | def setup_restart_handler(app: Client): 16 | 17 | @app.on_message(filters.command(["restart", "reboot", "reload"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 18 | async def restart(client, message): 19 | user_id = message.from_user.id 20 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 21 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 22 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 23 | LOGGER.info("User not admin or owner, sending restricted message") 24 | await client.send_message( 25 | chat_id=message.chat.id, 26 | text="✘Kids Not Allowed To Do This↯", 27 | parse_mode=ParseMode.HTML, 28 | reply_markup=InlineKeyboardMarkup( 29 | [ 30 | [ 31 | InlineKeyboardButton("👨🏼‍💻 Developer", url="https://t.me/abirxdhackz"), 32 | InlineKeyboardButton("🤖 Other Bots", url=UPDATE_CHANNEL_URL) 33 | ], 34 | [ 35 | InlineKeyboardButton("🔗 Source Code", url="https://github.com/abirxdhack/RestartModule"), 36 | InlineKeyboardButton("🔔 Update News", url=UPDATE_CHANNEL_URL) 37 | ] 38 | ] 39 | ) 40 | ) 41 | return 42 | 43 | LOGGER.info(f"Restart command initiated by user {user_id}") 44 | response = await client.send_message( 45 | chat_id=message.chat.id, 46 | text="SecureXTools Restarting....", 47 | parse_mode=ParseMode.HTML 48 | ) 49 | 50 | # Directories to be removed 51 | directories = ["downloads", "temp", "temp_media", "data", "repos"] 52 | for directory in directories: 53 | try: 54 | shutil.rmtree(directory) 55 | LOGGER.info(f"Removed directory: {directory}") 56 | except FileNotFoundError: 57 | LOGGER.debug(f"Directory not found: {directory}") 58 | except Exception as e: 59 | LOGGER.error(f"Failed to remove directory {directory}: {e}") 60 | 61 | # Delete the botlogs.txt file if it exists 62 | if os.path.exists("botlog.txt"): 63 | try: 64 | os.remove("botlog.txt") 65 | LOGGER.info("Removed botlog.txt") 66 | except Exception as e: 67 | LOGGER.error(f"Failed to remove botlog.txt: {e}") 68 | 69 | # Delete session files (assuming session name is "SecureXTools"; replace with actual session name or import from config if different) 70 | session_files = ["SecureXTools.session-journal"] 71 | deleted = [] 72 | not_deleted = [] 73 | for file in session_files: 74 | try: 75 | os.remove(file) 76 | deleted.append(file) 77 | LOGGER.info(f"Removed session file: {file}") 78 | except FileNotFoundError: 79 | LOGGER.debug(f"Session file not found: {file}") 80 | except Exception as e: 81 | not_deleted.append(file) 82 | LOGGER.error(f"Failed to delete session file {file}: {e}") 83 | 84 | # Construct status message for session file deletion 85 | status_parts = [] 86 | if deleted: 87 | status_parts.append(f"Deleted: {', '.join(deleted)}") 88 | if not_deleted: 89 | status_parts.append(f"Failed to delete: {', '.join(not_deleted)}") 90 | status = "No session files to delete." if not status_parts else " ".join(status_parts) 91 | LOGGER.info(f"Session file deletion status: {status}") 92 | 93 | await asyncio.sleep(10) 94 | 95 | await client.edit_message_text( 96 | chat_id=message.chat.id, 97 | message_id=response.id, 98 | text=f"SecureXTools Successfully Restarted!", 99 | parse_mode=ParseMode.HTML 100 | ) 101 | LOGGER.info("Bot restart completed, executing system restart") 102 | os.system(f"kill -9 {os.getpid()} && bash start.sh") 103 | 104 | @app.on_message(filters.command(["stop", "kill", "off"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 105 | async def stop(client, message): 106 | user_id = message.from_user.id 107 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 108 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 109 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 110 | LOGGER.info("User not admin or owner, sending restricted message") 111 | await client.send_message( 112 | chat_id=message.chat.id, 113 | text="✘Kids Not Allowed To Do This↯", 114 | parse_mode=ParseMode.HTML, 115 | reply_markup=InlineKeyboardMarkup( 116 | [ 117 | [ 118 | InlineKeyboardButton("👨🏼‍💻 Developer", url="https://t.me/abirxdhackz"), 119 | InlineKeyboardButton("🤖 Other Bots", url=UPDATE_CHANNEL_URL) 120 | ], 121 | [ 122 | InlineKeyboardButton("🔗 Source Code", url="https://github.com/abirxdhack/RestartModule"), 123 | InlineKeyboardButton("🔔 Update News", url=UPDATE_CHANNEL_URL) 124 | ] 125 | ] 126 | ) 127 | ) 128 | return 129 | 130 | LOGGER.info(f"Stop command initiated by user {user_id}") 131 | await client.send_message( 132 | chat_id=message.chat.id, 133 | text="Bot Off Successfully All Database Cleared", 134 | parse_mode=ParseMode.HTML 135 | ) 136 | LOGGER.info("Bot stop executed, terminating process") 137 | os.system("pkill -f main.py") 138 | -------------------------------------------------------------------------------- /sudoers/gban/gban.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | from pyrogram import Client, filters 5 | from pyrogram.errors import UserIdInvalid, UsernameInvalid, PeerIdInvalid 6 | from config import OWNER_ID, COMMAND_PREFIX 7 | from core import auth_admins, banned_users 8 | from utils import LOGGER 9 | 10 | def setup_gban_handler(app: Client): 11 | @app.on_message(filters.command(["gban"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 12 | async def gban_command(client, message): 13 | user_id = message.from_user.id 14 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 15 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 16 | 17 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 18 | sent_message = await client.send_message(message.chat.id, "**✘Kids Not Allowed To Do This↯**") 19 | LOGGER.info(f"Unauthorized gban attempt by user {user_id}") 20 | return 21 | 22 | # Check if a user is specified 23 | if len(message.command) < 2 and not message.reply_to_message: 24 | sent_message = await client.send_message(message.chat.id, "**✘Please Specify User To Ban Forever↯**") 25 | return 26 | 27 | # Get target user 28 | target_user = None 29 | target_identifier = None 30 | if message.reply_to_message and message.reply_to_message.from_user: 31 | target_user = message.reply_to_message.from_user 32 | target_identifier = target_user.id 33 | else: 34 | target_identifier = message.command[1] 35 | try: 36 | # Try to resolve as user ID first 37 | target_user = await client.get_users(int(target_identifier)) 38 | except (ValueError, UserIdInvalid, PeerIdInvalid): 39 | try: 40 | # If not a valid user ID, try as username 41 | target_identifier = target_identifier.lstrip('@') 42 | target_user = await client.get_users(target_identifier) 43 | except (UsernameInvalid, PeerIdInvalid) as e: 44 | sent_message = await client.send_message(message.chat.id, "**✘Error: Invalid User ID/Username↯**") 45 | LOGGER.error(f"Error resolving user {target_identifier}: {e}") 46 | return 47 | 48 | target_id = target_user.id 49 | target_name = target_user.username or target_user.first_name or str(target_id) 50 | 51 | # Check if user is already banned 52 | if banned_users.find_one({"user_id": target_id}): 53 | sent_message = await client.send_message(message.chat.id, f"**✘User {target_name} is already banned↯**") 54 | return 55 | 56 | # Ban the user 57 | banned_users.insert_one({"user_id": target_id, "username": target_name}) 58 | 59 | # Notify the banned user 60 | try: 61 | await client.send_message(target_id, "**✘Bro You're Banned Forever↯**") 62 | except Exception as e: 63 | LOGGER.error(f"Failed to notify banned user {target_id}: {e}") 64 | 65 | # Notify owner and admins 66 | sent_message = await client.send_message(message.chat.id, f"**✘Successfully Banned {target_name}↯**") 67 | for admin_id in [OWNER_ID] + AUTH_ADMIN_IDS: 68 | if admin_id != user_id: 69 | try: 70 | await client.send_message(admin_id, f"**✘Successfully Banned {target_name}↯**") 71 | except Exception as e: 72 | LOGGER.error(f"Failed to notify admin {admin_id}: {e}") 73 | 74 | @app.on_message(filters.command(["gunban"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 75 | async def gunban_command(client, message): 76 | user_id = message.from_user.id 77 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 78 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 79 | 80 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 81 | sent_message = await client.send_message(message.chat.id, "**✘Kids Not Allowed To Do This↯**") 82 | LOGGER.info(f"Unauthorized gunban attempt by user {user_id}") 83 | return 84 | 85 | # Check if a user is specified 86 | if len(message.command) < 2 and not message.reply_to_message: 87 | sent_message = await client.send_message(message.chat.id, "**✘Please Specify User To UnBan ↯**") 88 | return 89 | 90 | # Get target user 91 | target_user = None 92 | target_identifier = None 93 | if message.reply_to_message and message.reply_to_message.from_user: 94 | target_user = message.reply_to_message.from_user 95 | target_identifier = target_user.id 96 | else: 97 | target_identifier = message.command[1] 98 | try: 99 | # Try to resolve as user ID first 100 | target_user = await client.get_users(int(target_identifier)) 101 | except (ValueError, UserIdInvalid, PeerIdInvalid): 102 | try: 103 | # If not a valid user ID, try as username 104 | target_identifier = target_identifier.lstrip('@') 105 | target_user = await client.get_users(target_identifier) 106 | except (UsernameInvalid, PeerIdInvalid) as e: 107 | sent_message = await client.send_message(message.chat.id, "**✘Error: Invalid User ID/Username↯**") 108 | LOGGER.error(f"Error resolving user {target_identifier}: {e}") 109 | return 110 | 111 | target_id = target_user.id 112 | target_name = target_user.username or target_user.first_name or str(target_id) 113 | 114 | # Check if user is banned 115 | if not banned_users.find_one({"user_id": target_id}): 116 | sent_message = await client.send_message(message.chat.id, f"**✘User {target_name} is not banned↯**") 117 | return 118 | 119 | # Unban the user 120 | banned_users.delete_one({"user_id": target_id}) 121 | 122 | # Notify the unbanned user 123 | try: 124 | await client.send_message(target_id, "**✘Bro You're Unbanned↯**") 125 | except Exception as e: 126 | LOGGER.error(f"Failed to notify unbanned user {target_id}: {e}") 127 | 128 | # Notify owner and admins 129 | sent_message = await client.send_message(message.chat.id, f"**✘Successfully Unbanned {target_name}↯**") 130 | for admin_id in [OWNER_ID] + AUTH_ADMIN_IDS: 131 | if admin_id != user_id: 132 | try: 133 | await client.send_message(admin_id, f"**✘Successfully Unbanned {target_name}↯**") 134 | except Exception as e: 135 | LOGGER.error(f"Failed to notify admin {admin_id}: {e}") 136 | -------------------------------------------------------------------------------- /modules/netxutils/px.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import asyncio 5 | import socket 6 | import aiohttp 7 | from pyrogram import Client, filters 8 | from pyrogram.types import Message 9 | from config import COMMAND_PREFIX, PROXY_CHECK_LIMIT 10 | from utils import LOGGER, notify_admin # Use LOGGER and notify_admin 11 | from core import banned_users # Use banned_users 12 | 13 | PROXY_TIMEOUT = 10 14 | GEOLOCATION_TIMEOUT = 3 15 | 16 | class HTTPProxyChecker: 17 | def __init__(self): 18 | self.geo_service = { 19 | 'name': 'ipinfo.io', 20 | 'url': "https://ipinfo.io/{ip}/json", 21 | 'parser': lambda data: f"{data.get('region', 'Unknown')} ({data.get('country', 'Unknown')})", 22 | 'headers': {'User-Agent': 'Mozilla/5.0'} 23 | } 24 | 25 | async def get_location(self, session, ip): 26 | try: 27 | url = self.geo_service['url'].format(ip=ip) 28 | async with session.get( 29 | url, 30 | headers=self.geo_service.get('headers', {}), 31 | timeout=GEOLOCATION_TIMEOUT 32 | ) as response: 33 | data = await response.json() 34 | LOGGER.info(f"Location API Response: {data}") 35 | if response.status == 200: 36 | return self.geo_service['parser'](data) 37 | return f"❌ HTTP {response.status}" 38 | except asyncio.TimeoutError: 39 | return "⏳ Timeout" 40 | except Exception as e: 41 | LOGGER.error(f"Error fetching location: {e}") 42 | return f"❌ Error ({str(e)[:30]})" 43 | 44 | async def check_anonymity(self, session, proxy_url): 45 | try: 46 | async with session.get( 47 | "http://httpbin.org/headers", 48 | proxy=proxy_url, 49 | timeout=PROXY_TIMEOUT, 50 | headers={'User-Agent': 'Mozilla/5.0'} 51 | ) as response: 52 | if response.status == 200: 53 | headers_data = await response.json() 54 | client_headers = headers_data.get('headers', {}) 55 | if 'X-Forwarded-For' in client_headers: 56 | return 'Transparent' 57 | elif 'Via' in client_headers: 58 | return 'Anonymous' 59 | else: 60 | return 'Elite' 61 | return 'Unknown' 62 | except: 63 | return 'Unknown' 64 | 65 | async def check_proxy(self, proxy, proxy_type='http', auth=None): 66 | result = { 67 | 'proxy': f"{proxy}", 68 | 'status': 'Dead 🔴', 69 | 'location': '• Not determined', 70 | 'anonymity': 'Unknown' 71 | } 72 | 73 | ip = proxy.split(':')[0] 74 | 75 | try: 76 | proxy_url = f"{proxy_type}://{auth['username']}:{auth['password']}@{proxy}" if auth else f"{proxy_type}://{proxy}" 77 | connector = aiohttp.TCPConnector() 78 | 79 | async with aiohttp.ClientSession(connector=connector) as session: 80 | async with session.get( 81 | "http://httpbin.org/ip", 82 | proxy=proxy_url, 83 | timeout=PROXY_TIMEOUT, 84 | headers={'User-Agent': 'Mozilla/5.0'} 85 | ) as response: 86 | data = await response.json() 87 | LOGGER.info(f"Proxy Check API Response: {data}") 88 | if response.status == 200: 89 | result.update({ 90 | 'status': 'Live ✅', 91 | 'ip': ip 92 | }) 93 | result['anonymity'] = await self.check_anonymity(session, proxy_url) 94 | 95 | result['location'] = await self.get_location(session, ip) 96 | 97 | except Exception as e: 98 | LOGGER.error(f"Error checking proxy: {e}") 99 | async with aiohttp.ClientSession() as session: 100 | result['location'] = await self.get_location(session, ip) 101 | 102 | return result 103 | 104 | checker = HTTPProxyChecker() 105 | 106 | def setup_px_handler(app): 107 | @app.on_message(filters.command(["px", "proxy"], prefixes=COMMAND_PREFIX) & (filters.group | filters.private)) 108 | async def px_command_handler(client, message: Message): 109 | user_id = message.from_user.id if message.from_user else None 110 | if user_id and banned_users.find_one({"user_id": user_id}): 111 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**") 112 | return 113 | 114 | args = message.text.split()[1:] 115 | if len(args) > 0: 116 | if len(args) >= 3 and ':' not in args[-1] and ':' not in args[-2]: 117 | auth = {'username': args[-2], 'password': args[-1]} 118 | proxy_args = args[:-2] 119 | else: 120 | auth = None 121 | proxy_args = args 122 | else: 123 | if message.reply_to_message and message.reply_to_message.text: 124 | proxy_text = message.reply_to_message.text 125 | potential_proxies = proxy_text.split() 126 | proxy_args = [p for p in potential_proxies if ':' in p] 127 | auth = None 128 | else: 129 | return await client.send_message( 130 | message.chat.id, 131 | "❌ Provide at least one proxy for check" 132 | ) 133 | 134 | if len(proxy_args) > PROXY_CHECK_LIMIT: 135 | return await client.send_message( 136 | message.chat.id, 137 | " ❌ Sorry Bro Maximum Proxy Check Limit Is 20 " 138 | ) 139 | 140 | proxies_to_check = [] 141 | for proxy in proxy_args: 142 | if '://' in proxy: 143 | parts = proxy.split('://') 144 | if len(parts) == 2 and parts[0].lower() in ['http', 'https']: 145 | proxy_type = parts[0].lower() 146 | proxy_addr = parts[1] 147 | if ':' in proxy_addr: 148 | proxies_to_check.append((proxy_type, proxy_addr)) 149 | else: 150 | if ':' in proxy: 151 | proxies_to_check.append(('http', proxy)) 152 | 153 | if not proxies_to_check: 154 | return await client.send_message( 155 | message.chat.id, 156 | "❌ The Proxies Are Not Valid At All" 157 | ) 158 | 159 | processing_msg = await client.send_message( 160 | chat_id=message.chat.id, 161 | text=f" Smart Proxy Checker Checking Proxies 💥" 162 | ) 163 | 164 | try: 165 | tasks = [checker.check_proxy(proxy, proxy_type, auth) for proxy_type, proxy in proxies_to_check] 166 | results = await asyncio.gather(*tasks) 167 | await send_results(client, message, processing_msg, results) 168 | except Exception as e: 169 | LOGGER.error(f"Error during proxy check: {e}") 170 | await processing_msg.edit_text("Sorry Bro Proxy Checker API Dead") 171 | await notify_admin(client, "/px", e, message) 172 | 173 | async def send_results(client, original_msg, processing_msg, results): 174 | response = [] 175 | 176 | for res in results: 177 | response.append(f"Proxy: {res['proxy']}\n") 178 | response.append(f"Status: {res['status']}\n") 179 | if res['status'] == 'Live ✅': 180 | response.append(f"Anonymity: {res['anonymity']}\n") 181 | response.append(f"Region: {res['location']}\n") 182 | response.append("\n") 183 | 184 | full_response = ''.join(response) 185 | await processing_msg.edit_text(full_response) -------------------------------------------------------------------------------- /modules/dlxutils/tik.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import time 6 | import re 7 | from pathlib import Path 8 | from typing import Optional 9 | import aiohttp 10 | import aiofiles 11 | import requests 12 | from pyrogram import Client, filters 13 | from pyrogram.types import Message 14 | from pyrogram.enums import ParseMode 15 | from config import COMMAND_PREFIX 16 | from utils import LOGGER, progress_bar, notify_admin # Import LOGGER, progress_bar, and notify_admin from utils 17 | from core import banned_users # Check if user is banned 18 | 19 | # Use the imported LOGGER 20 | logger = LOGGER 21 | 22 | # Configuration 23 | class Config: 24 | TEMP_DIR = Path("temp") 25 | 26 | Config.TEMP_DIR.mkdir(exist_ok=True) 27 | 28 | async def sanitize_filename(title: str) -> str: 29 | """Sanitize file name by removing invalid characters.""" 30 | title = re.sub(r'[<>:"/\\|?*]', '', title[:50]).strip() 31 | return f"{title.replace(' ', '_')}_{int(time.time())}" 32 | 33 | async def download_video(url: str, downloading_message: Message) -> Optional[dict]: 34 | """Download video from TikTok URL using API.""" 35 | api_url = "https://downloader.bot/api/tiktok/info" 36 | payload = {"url": url} 37 | headers = { 38 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", 39 | "Referer": "https://downloader.bot" 40 | } 41 | 42 | try: 43 | response = requests.post(api_url, json=payload, headers=headers) 44 | response.raise_for_status() 45 | data = response.json() 46 | 47 | if data.get("error"): 48 | logger.error(f"API error: {data['error']}") 49 | # Notify admins 50 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}tt", Exception(f"API error: {data['error']}"), downloading_message) 51 | return None 52 | 53 | info = data["data"] 54 | video_url = info.get("mp4") 55 | if not video_url: 56 | logger.error("No video URL found in API response") 57 | # Notify admins 58 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}tt", Exception("No video URL found in API response"), downloading_message) 59 | return None 60 | 61 | await downloading_message.edit_text("**Found ☑️ Downloading...**", parse_mode=ParseMode.MARKDOWN) 62 | 63 | title = info.get("title", "TikTok_Video") 64 | safe_title = await sanitize_filename(title) 65 | video_output = Config.TEMP_DIR / f"{safe_title}.mp4" 66 | 67 | async with aiohttp.ClientSession() as session: 68 | async with session.get(video_url, headers=headers) as video_response: 69 | if video_response.status == 200: 70 | async with aiofiles.open(video_output, 'wb') as f: 71 | async for chunk in video_response.content.iter_chunked(8192): 72 | await f.write(chunk) 73 | logger.info(f"Video downloaded successfully to: {video_output}") 74 | return { 75 | 'filename': str(video_output), 76 | 'title': title, 77 | 'webpage_url': url 78 | } 79 | else: 80 | logger.error(f"Failed to download video: HTTP {video_response.status}") 81 | # Notify admins 82 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}tt", Exception(f"Failed to download video: HTTP {video_response.status}"), downloading_message) 83 | return None 84 | except Exception as e: 85 | logger.error(f"Error downloading video: {e}") 86 | # Notify admins 87 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}tt", e, downloading_message) 88 | return None 89 | 90 | def setup_tt_handler(app: Client): 91 | # Create a regex pattern from the COMMAND_PREFIX list 92 | command_prefix_regex = f"[{''.join(map(re.escape, COMMAND_PREFIX))}]" 93 | 94 | @app.on_message(filters.regex(rf"^{command_prefix_regex}tt(\s+https?://\S+)?$") & (filters.private | filters.group)) 95 | async def tiktok_handler(client: Client, message: Message): 96 | # Check if user is banned 97 | user_id = message.from_user.id if message.from_user else None 98 | if user_id and banned_users.find_one({"user_id": user_id}): 99 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**") 100 | return 101 | 102 | url = None 103 | # Check if the message is a reply to another message containing a URL 104 | if message.reply_to_message and message.reply_to_message.text: 105 | replied_text = message.reply_to_message.text 106 | if re.match(r'https?://\S+', replied_text): 107 | url = replied_text 108 | 109 | # If no URL from reply, check the command arguments 110 | if not url: 111 | command_parts = message.text.split(maxsplit=1) 112 | if len(command_parts) < 2: 113 | await client.send_message( 114 | chat_id=message.chat.id, 115 | text="**Please provide a TikTok link ❌**", 116 | parse_mode=ParseMode.MARKDOWN 117 | ) 118 | logger.warning(f"No TikTok URL provided, user: {user_id or 'unknown'}, chat: {message.chat.id}") 119 | return 120 | url = command_parts[1] 121 | 122 | status_message = await client.send_message( 123 | chat_id=message.chat.id, 124 | text="**Searching The Video...**", 125 | parse_mode=ParseMode.MARKDOWN 126 | ) 127 | 128 | try: 129 | video_info = await download_video(url, status_message) 130 | if not video_info: 131 | await status_message.edit_text("**❌ Invalid Video URL Inputted**", parse_mode=ParseMode.MARKDOWN) 132 | logger.error(f"Failed to download video for URL: {url}") 133 | return 134 | 135 | title = video_info['title'] 136 | filename = video_info['filename'] 137 | webpage_url = video_info['webpage_url'] 138 | 139 | if message.from_user: 140 | user_full_name = f"{message.from_user.first_name} {message.from_user.last_name or ''}".strip() 141 | user_info = f"[{user_full_name}](tg://user?id={message.from_user.id})" 142 | else: 143 | group_name = message.chat.title or "this group" 144 | group_url = f"https://t.me/{message.chat.username}" if message.chat.username else "this group" 145 | user_info = f"[{group_name}]({group_url})" 146 | 147 | caption = ( 148 | f"🎵 **Title**: **{title}**\n" 149 | f"━━━━━━━━━━━━━━━━━━━━━\n" 150 | f"🔗 **Url**: [Watch On TikTok]({webpage_url})\n" 151 | f"━━━━━━━━━━━━━━━━━━━━━\n" 152 | f"**Downloaded By**: {user_info}" 153 | ) 154 | 155 | start_time = time.time() 156 | last_update_time = [start_time] 157 | 158 | await client.send_video( 159 | chat_id=message.chat.id, 160 | video=filename, 161 | caption=caption, 162 | parse_mode=ParseMode.MARKDOWN, 163 | supports_streaming=True, 164 | progress=progress_bar, 165 | progress_args=(status_message, start_time, last_update_time) 166 | ) 167 | 168 | await status_message.delete() 169 | if os.path.exists(filename): 170 | os.remove(filename) 171 | logger.info(f"Deleted the video file: {filename}") 172 | 173 | except Exception as e: 174 | logger.error(f"An error occurred: {e}") 175 | # Notify admins 176 | await notify_admin(client, f"{COMMAND_PREFIX}tt", e, message) 177 | # Send user-facing error message 178 | await status_message.edit_text("**TikTok Downloader API Dead**", parse_mode=ParseMode.MARKDOWN) -------------------------------------------------------------------------------- /modules/hlpxutils/help.py: -------------------------------------------------------------------------------- 1 | #Copyright @ISmartDevs 2 | #Channel t.me/TheSmartDev 3 | 4 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 5 | from pyrogram.enums import ParseMode, ChatType 6 | from config import BOT_USERNAME, OWNER_ID, UPDATE_CHANNEL_URL, BOT_NAME, COMMAND_PREFIX 7 | from utils import LOGGER 8 | from core import banned_users 9 | from pyrogram import filters 10 | import os 11 | 12 | def setup_help_handler(app): 13 | @app.on_message(filters.command(["help", "tutorial"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 14 | async def help_message(client, message): 15 | user_id = message.from_user.id if message.from_user else None 16 | if user_id and banned_users.find_one({"user_id": user_id}): 17 | await client.send_message(message.chat.id, "**✘ Sorry You're Banned From Using Me↯**") 18 | return 19 | 20 | user = message.from_user 21 | full_name = (user.first_name or "") + (f" {user.last_name}" if user and user.last_name else "") 22 | full_name = full_name.strip() or "User" 23 | user_mention = f"[{full_name}](tg://user?id={user.id})" if user else "User" 24 | 25 | if message.chat.type == ChatType.PRIVATE: 26 | help_text = ( 27 | f"**This bot helps you manage your groups and provides various tools.**\n\n" 28 | "**Here are the available commands:**\n" 29 | "**━━━━━━━━━━━━━━━━**\n" 30 | "**/info** - **Get User Information.**\n" 31 | "**/id** - **Get Group & Channel Information.**\n" 32 | "**/ip** - **Get IP information.**\n" 33 | "**/px** - **Http/Https Proxy Checker.**\n" 34 | "**/ss** - **Take Screenshot of Website.**\n" 35 | "**/fb** - **Download Facebook video.**\n" 36 | "**/in** - **Download Instagram Photos, Reel Or Stories.**\n" 37 | "**/sp Or Send Direct Url** - **Download Spotify Track/Album Or Playlist.**\n" 38 | "**/song** - **Download Music or Youtube as Mp3 Format.**\n" 39 | "**/video** - **Download Youtube Video.**\n" 40 | "**/tt** - **Download Tiktok Video.**\n" 41 | "**/pnt** - **Download Pinterest Video.**" 42 | ) 43 | else: 44 | group_name = message.chat.title if message.chat.title else "this group" 45 | help_text = ( 46 | f"**Hey {user_mention}, Welcome to {group_name}!**\n" 47 | f"**This bot helps you manage your groups and provides various tools.**\n\n" 48 | "**Here are the available commands:**\n" 49 | "**━━━━━━━━━━━━━━━━**\n" 50 | "**/info** - **Get User Information.**\n" 51 | "**/id** - **Get Group & Channel Information.**\n" 52 | "**/ip** - **Get IP information.**\n" 53 | "**/px** - **Http/Https Proxy Checker.**\n" 54 | "**/ss** - **Take Screenshot of Website.**\n" 55 | "**/fb** - **Download Facebook video.**\n" 56 | "**/in** - **Download Instagram Photos, Reel Or Stories.**\n" 57 | "**/sp Or Send Direct Url** - **Download Spotify Track/Album Or Playlist.**\n" 58 | "**/song** - **Download Music or Youtube as Mp3 Format.**\n" 59 | "**/video** - **Download Youtube Video.**\n" 60 | "**/tt** - **Download Tiktok Video.**\n" 61 | "**/pnt** - **Download Pinterest Video.**" 62 | ) 63 | 64 | buttons = InlineKeyboardMarkup([ 65 | [ 66 | InlineKeyboardButton("Back to Start", callback_data="backtostartmsg"), 67 | InlineKeyboardButton("Close", callback_data="Closemsg") 68 | ] 69 | ]) 70 | 71 | await client.send_message( 72 | chat_id=message.chat.id, 73 | text=help_text, 74 | parse_mode=ParseMode.MARKDOWN, 75 | reply_markup=buttons, 76 | disable_web_page_preview=True, 77 | ) 78 | LOGGER.info(f"Sent help message to chat {message.chat.id}") 79 | 80 | @app.on_callback_query(filters.regex("backtostartmsg|helpmenu|Closemsg")) 81 | async def handle_callback_query(client, callback_query): 82 | LOGGER.info(f"Processing callback '{callback_query.data}' from user {callback_query.from_user.id}") 83 | 84 | user = callback_query.from_user 85 | full_name = (user.first_name or "") + (f" {user.last_name}" if user.last_name else "") 86 | full_name = full_name.strip() or "User" 87 | user_mention = f"[{full_name}](tg://user?id={user.id})" 88 | 89 | if callback_query.data == "helpmenu": 90 | help_text = ( 91 | "**This bot helps you manage your groups and provides various tools.**\n\n" 92 | "**Here are the available commands:**\n" 93 | "**━━━━━━━━━━━━━━━━**\n" 94 | "**/info** - **Get User Information.**\n" 95 | "**/id** - **Get Group & Channel Information.**\n" 96 | "**/ip** - **Get IP information.**\n" 97 | "**/px** - **Http/Https Proxy Checker.**\n" 98 | "**/ss** - **Take Screenshot of Website.**\n" 99 | "**/fb** - **Download Facebook video.**\n" 100 | "**/in** - **Download Instagram Photos, Reel Or Stories.**\n" 101 | "**/sp ** - **Download Spotify Track/Album Or Playlist.**\n" 102 | "**/song** - **Download Music or Youtube as Mp3 Format.**\n" 103 | "**/video** - **Download Youtube Video.**\n" 104 | "**/tt** - **Download Tiktok Video.**\n" 105 | "**/pnt** - **Download Pinterest Video.**" 106 | ) 107 | buttons = InlineKeyboardMarkup( 108 | [ 109 | [ 110 | InlineKeyboardButton("Back", callback_data="backtostartmsg"), 111 | InlineKeyboardButton("Close", callback_data="Closemsg") 112 | ] 113 | ] 114 | ) 115 | await client.edit_message_text( 116 | chat_id=callback_query.message.chat.id, 117 | message_id=callback_query.message.id, 118 | text=help_text, 119 | reply_markup=buttons, 120 | parse_mode=ParseMode.MARKDOWN 121 | ) 122 | LOGGER.info(f"Edited message to show help menu for user {user.id}") 123 | 124 | elif callback_query.data == "backtostartmsg": 125 | welcome_text = ( 126 | f"**◑ ʜᴇʏ {user_mention}, ᴡᴇʟᴄᴏᴍᴇ ᴛᴏ ᴛʜᴇ ʙᴏᴛ**\n" 127 | f"**➻ ᴛʜɪs ɪs [{BOT_NAME}](t.me/{BOT_USERNAME.lstrip('@')}), ᴀ ғᴀsᴛ & ᴘᴏᴡᴇʀғᴜʟ ᴛᴏᴏʟᴋɪᴛ.**\n" 128 | "**━━━━━━━━━━━━━━━━━━━━━━**\n" 129 | "**Tᴏᴏʟs:** ᴛᴇʟᴇɢʀᴀᴍ ᴜsᴇʀ ɪɴғᴏ ᴄʜᴇᴄᴋᴇʀ, ɪᴘ ᴄʜᴇᴄᴋᴇʀ, ᴘʀᴏxʏ ᴄʜᴇᴄᴋᴇʀ, sᴄʀᴇᴇɴsʜᴏᴛ.\n\n" 130 | "**ᴅᴏᴡɴʟᴏᴀᴅ ᴘʟᴀᴛғᴏʀᴍs:** ʏᴏᴜᴛᴜʙᴇ, ғᴀᴄᴇʙᴏᴏᴋ, ɪɴsᴛᴀɢʀᴀᴍ, ᴘɪɴᴛᴇʀᴇsᴛ, sᴘᴏᴛɪғʏ, ᴛɪᴋᴛᴏᴋ." 131 | ) 132 | buttons = InlineKeyboardMarkup( 133 | [ 134 | [InlineKeyboardButton("➕ Add Me", url=f"https://t.me/{BOT_USERNAME.lstrip('@')}?startgroup=true")], 135 | [ 136 | InlineKeyboardButton("🔧 Developer", user_id=OWNER_ID), 137 | InlineKeyboardButton("✍🏻 Support", url=UPDATE_CHANNEL_URL) 138 | ], 139 | [InlineKeyboardButton("ℹ️ Help & Command", callback_data="helpmenu")] 140 | ] 141 | ) 142 | photo_path = "assets/wlc.jpg" 143 | 144 | if os.path.exists(photo_path): 145 | await client.send_photo( 146 | chat_id=callback_query.message.chat.id, 147 | photo=photo_path, 148 | caption=welcome_text, 149 | parse_mode=ParseMode.MARKDOWN, 150 | reply_markup=buttons 151 | ) 152 | await client.delete_messages( 153 | chat_id=callback_query.message.chat.id, 154 | message_ids=callback_query.message.id 155 | ) 156 | LOGGER.info(f"Sent welcome photo message and deleted original for user {user.id}") 157 | else: 158 | await client.edit_message_text( 159 | chat_id=callback_query.message.chat.id, 160 | message_id=callback_query.message.id, 161 | text=welcome_text, 162 | reply_markup=buttons, 163 | parse_mode=ParseMode.MARKDOWN 164 | ) 165 | LOGGER.warning(f"Photo {photo_path} not found, edited message to show welcome message for user {user.id}") 166 | 167 | elif callback_query.data == "Closemsg": 168 | await client.delete_messages( 169 | chat_id=callback_query.message.chat.id, 170 | message_ids=callback_query.message.id 171 | ) 172 | LOGGER.info(f"Deleted message for user {user.id}") 173 | -------------------------------------------------------------------------------- /modules/dlxutils/pin.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import re 6 | import asyncio 7 | import time 8 | import aiohttp 9 | import aiofiles 10 | from pathlib import Path 11 | from typing import Optional 12 | from pyrogram import Client, filters 13 | from pyrogram.types import Message 14 | from pyrogram.enums import ParseMode 15 | from config import COMMAND_PREFIX 16 | from utils import LOGGER, progress_bar, notify_admin # Import LOGGER, progress_bar, and notify_admin from utils 17 | from core import banned_users # Check if user is banned 18 | 19 | # Use the imported LOGGER 20 | logger = LOGGER 21 | 22 | # Configuration 23 | class Config: 24 | TEMP_DIR = Path("temp") 25 | 26 | Config.TEMP_DIR.mkdir(exist_ok=True) 27 | 28 | class PinterestDownloader: 29 | def __init__(self, temp_dir: Path): 30 | self.temp_dir = temp_dir 31 | 32 | async def sanitize_filename(self, title: str) -> str: 33 | """Sanitize file name by removing invalid characters.""" 34 | title = re.sub(r'[<>:"/\\|?*]', '', title[:50]).strip() 35 | return f"{title.replace(' ', '_')}_{int(time.time())}" 36 | 37 | async def download_media(self, url: str, downloading_message: Message) -> Optional[dict]: 38 | self.temp_dir.mkdir(exist_ok=True) 39 | api_url = f"https://pin-ten-pi.vercel.app/dl?url={url}" 40 | 41 | try: 42 | async with aiohttp.ClientSession( 43 | connector=aiohttp.TCPConnector(limit=100), 44 | timeout=aiohttp.ClientTimeout(total=30) 45 | ) as session: 46 | async with session.get(api_url) as response: 47 | logger.info(f"API request to {api_url} returned status {response.status}") 48 | if response.status == 200: 49 | data = await response.json() 50 | logger.info(f"API response: {data}") 51 | media_url = data.get("dl_url") 52 | title = data.get("title", "Pinterest Media") 53 | if not media_url: 54 | logger.error("No download URL found in API response") 55 | await downloading_message.edit_text("**Unable To Extract Url**", parse_mode=ParseMode.MARKDOWN) 56 | return None 57 | await downloading_message.edit_text("**Found ☑️ Downloading...**", parse_mode=ParseMode.MARKDOWN) 58 | safe_title = await self.sanitize_filename(title) 59 | filename = self.temp_dir / f"{safe_title}.mp4" 60 | await self._download_file(session, media_url, filename) 61 | return { 62 | 'title': title, 63 | 'filename': str(filename), 64 | 'webpage_url': url 65 | } 66 | logger.error(f"API request failed: HTTP status {response.status}") 67 | return None 68 | except aiohttp.ClientError as e: 69 | logger.error(f"Pinterest download error: {e}") 70 | # Notify admins 71 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}pnt", e, downloading_message) 72 | return None 73 | except asyncio.TimeoutError: 74 | logger.error("Request to Pinterest API timed out") 75 | # Notify admins 76 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}pnt", asyncio.TimeoutError("Request to Pinterest API timed out"), downloading_message) 77 | return None 78 | except Exception as e: 79 | logger.error(f"Pinterest download error: {e}") 80 | # Notify admins 81 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}pnt", e, downloading_message) 82 | return None 83 | 84 | async def _download_file(self, session: aiohttp.ClientSession, url: str, dest: Path): 85 | try: 86 | async with session.get(url) as response: 87 | if response.status == 200: 88 | logger.info(f"Downloading media from {url} to {dest}") 89 | async with aiofiles.open(dest, mode='wb') as f: 90 | async for chunk in response.content.iter_chunked(1024 * 1024): # 1MB chunks 91 | await f.write(chunk) 92 | logger.info(f"Media downloaded successfully to {dest}") 93 | else: 94 | logger.error(f"Failed to download file: HTTP status {response.status}") 95 | raise Exception(f"Failed to download file: {response.status}") 96 | except aiohttp.ClientError as e: 97 | logger.error(f"Error downloading file from {url}: {e}") 98 | # Notify admins 99 | await notify_admin(None, f"{COMMAND_PREFIX}pnt", e, None) 100 | raise 101 | 102 | def setup_pinterest_handler(app: Client): 103 | pin_downloader = PinterestDownloader(Config.TEMP_DIR) 104 | 105 | # Create a regex pattern from the COMMAND_PREFIX list 106 | command_prefix_regex = f"[{''.join(map(re.escape, COMMAND_PREFIX))}]" 107 | 108 | @app.on_message( 109 | filters.regex(rf"^{command_prefix_regex}(pnt|pint)(\s+https?://\S+)?$") & 110 | (filters.private | filters.group) 111 | ) 112 | async def pin_handler(client: Client, message: Message): 113 | # Check if user is banned 114 | user_id = message.from_user.id if message.from_user else None 115 | if user_id and banned_users.find_one({"user_id": user_id}): 116 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**", parse_mode=ParseMode.MARKDOWN) 117 | return 118 | 119 | url = None 120 | # Check if URL from reply 121 | if message.reply_to_message and message.reply_to_message.text: 122 | match = re.search(r"https?://pin\.it/\S+", message.reply_to_message.text) 123 | if match: 124 | url = match.group(0) 125 | # Check if URL from command 126 | if not url: 127 | command_parts = message.text.split(maxsplit=1) 128 | if len(command_parts) > 1: 129 | match = re.search(r"https?://pin\.it/\S+", command_parts[1]) 130 | if match: 131 | url = match.group(0) 132 | 133 | if not url: 134 | await client.send_message( 135 | chat_id=message.chat.id, 136 | text="**Please provide a Pinterest link**", 137 | parse_mode=ParseMode.MARKDOWN 138 | ) 139 | logger.warning(f"No Pinterest URL provided, user: {user_id or 'unknown'}, chat: {message.chat.id}") 140 | return 141 | 142 | logger.info(f"Pinterest URL received: {url}, user: {user_id or 'unknown'}, chat: {message.chat.id}") 143 | downloading_message = await client.send_message( 144 | chat_id=message.chat.id, 145 | text="**Searching The Media**", 146 | parse_mode=ParseMode.MARKDOWN 147 | ) 148 | 149 | try: 150 | media_info = await pin_downloader.download_media(url, downloading_message) 151 | if not media_info: 152 | await downloading_message.edit_text("**Unable To Extract Url**", parse_mode=ParseMode.MARKDOWN) 153 | logger.error(f"Failed to download media for URL: {url}") 154 | return 155 | 156 | title = media_info['title'] 157 | filename = media_info['filename'] 158 | webpage_url = media_info['webpage_url'] 159 | 160 | if message.from_user: 161 | user_full_name = f"{message.from_user.first_name} {message.from_user.last_name or ''}".strip() 162 | user_info = f"[{user_full_name}](tg://user?id={user_id})" 163 | else: 164 | group_name = message.chat.title or "this group" 165 | group_url = f"https://t.me/{message.chat.username}" if message.chat.username else "this group" 166 | user_info = f"[{group_name}]({group_url})" 167 | 168 | caption = ( 169 | f"🎥 **Title**: `{title}`\n" 170 | f"━━━━━━━━━━━━━━━━━━━━━\n" 171 | f"🔗 **Link**: [Watch on Pinterest]({webpage_url})\n" 172 | f"━━━━━━━━━━━━━━━━━━━━━\n" 173 | f"**Downloaded By**: {user_info}" 174 | ) 175 | 176 | async with aiofiles.open(filename, 'rb'): 177 | start_time = time.time() 178 | last_update_time = [start_time] 179 | await client.send_video( 180 | chat_id=message.chat.id, 181 | video=filename, 182 | supports_streaming=True, 183 | caption=caption, 184 | parse_mode=ParseMode.MARKDOWN, 185 | progress=progress_bar, 186 | progress_args=(downloading_message, start_time, last_update_time) 187 | ) 188 | 189 | await downloading_message.delete() 190 | if os.path.exists(filename): 191 | os.remove(filename) 192 | logger.info(f"Deleted video file: {filename}") 193 | 194 | except Exception as e: 195 | logger.error(f"Error processing Pinterest media: {e}") 196 | # Notify admins 197 | await notify_admin(client, f"{COMMAND_PREFIX}pnt", e, downloading_message) 198 | # Send user-facing error message 199 | await downloading_message.edit_text("**Pinterest Downloader API Dead**", parse_mode=ParseMode.MARKDOWN) -------------------------------------------------------------------------------- /modules/dlxutils/fb.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import re 6 | import asyncio 7 | import time 8 | import aiohttp 9 | import aiofiles 10 | from pathlib import Path 11 | from typing import Optional 12 | from pyrogram import Client, filters 13 | from pyrogram.types import Message 14 | from pyrogram.enums import ParseMode 15 | from config import COMMAND_PREFIX 16 | from utils import LOGGER, progress_bar, notify_admin # Import LOGGER, progress_bar, and notify_admin from utils 17 | from core import banned_users # Check if user is banned 18 | 19 | # Use the imported LOGGER 20 | logger = LOGGER 21 | 22 | # Configuration 23 | class Config: 24 | TEMP_DIR = Path("temp") 25 | 26 | Config.TEMP_DIR.mkdir(exist_ok=True) 27 | 28 | class FacebookDownloader: 29 | def __init__(self, temp_dir: Path): 30 | self.temp_dir = temp_dir 31 | 32 | async def sanitize_filename(self, title: str) -> str: 33 | """Sanitize file name by removing invalid characters.""" 34 | title = re.sub(r'[<>:"/\\|?*]', '', title[:50]).strip() 35 | return f"{title.replace(' ', '_')}_{int(time.time())}" 36 | 37 | async def download_video(self, url: str, downloading_message: Message) -> Optional[dict]: 38 | self.temp_dir.mkdir(exist_ok=True) 39 | api_url = f"https://tooly.chative.io/facebook/video?url={url}" 40 | 41 | try: 42 | async with aiohttp.ClientSession( 43 | connector=aiohttp.TCPConnector(limit_per_host=10), 44 | timeout=aiohttp.ClientTimeout(total=30) 45 | ) as session: 46 | async with session.get(api_url) as response: 47 | logger.info(f"API request to {api_url} returned status {response.status}") 48 | if response.status == 200: 49 | data = await response.json() 50 | logger.info(f"API response: {data}") 51 | if data.get("success"): 52 | video_url = data["videos"].get("hd", {}).get("url") 53 | if not video_url: 54 | logger.error("No HD video URL found in API response") 55 | await downloading_message.edit_text("**Unable To Extract Video URL**", parse_mode=ParseMode.MARKDOWN) 56 | return None 57 | await downloading_message.edit_text("**Found ☑️ Downloading...**", parse_mode=ParseMode.MARKDOWN) 58 | title = data.get("title", "Facebook Video") 59 | safe_title = await self.sanitize_filename(title) 60 | filename = self.temp_dir / f"{safe_title}.mp4" 61 | await self._download_file(session, video_url, filename) 62 | return { 63 | 'title': title, 64 | 'filename': str(filename), 65 | 'webpage_url': url 66 | } 67 | logger.error("API response indicates failure") 68 | return None 69 | logger.error(f"API request failed: HTTP status {response.status}") 70 | return None 71 | except aiohttp.ClientError as e: 72 | logger.error(f"Facebook download error: {e}") 73 | # Notify admins 74 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}fb", e, downloading_message) 75 | return None 76 | except asyncio.TimeoutError: 77 | logger.error("Request to Facebook API timed out") 78 | # Notify admins 79 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}fb", asyncio.TimeoutError("Request to Facebook API timed out"), downloading_message) 80 | return None 81 | except Exception as e: 82 | logger.error(f"Facebook download error: {e}") 83 | # Notify admins 84 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}fb", e, downloading_message) 85 | return None 86 | 87 | async def _download_file(self, session: aiohttp.ClientSession, url: str, dest: Path): 88 | try: 89 | async with session.get(url) as response: 90 | if response.status == 200: 91 | logger.info(f"Downloading video from {url} to {dest}") 92 | async with aiofiles.open(dest, mode='wb') as f: 93 | async for chunk in response.content.iter_chunked(1024 * 1024): # 1MB chunks 94 | await f.write(chunk) 95 | logger.info(f"Video downloaded successfully to {dest}") 96 | else: 97 | logger.error(f"Failed to download file: HTTP status {response.status}") 98 | raise Exception(f"Failed to download file: HTTP status {response.status}") 99 | except aiohttp.ClientError as e: 100 | logger.error(f"Error downloading file from {url}: {e}") 101 | # Notify admins 102 | await notify_admin(None, f"{COMMAND_PREFIX}fb", e, None) 103 | raise 104 | 105 | def setup_fb_handlers(app: Client): 106 | fb_downloader = FacebookDownloader(Config.TEMP_DIR) 107 | 108 | # Create a regex pattern from the COMMAND_PREFIX list 109 | command_prefix_regex = f"[{''.join(map(re.escape, COMMAND_PREFIX))}]" 110 | 111 | @app.on_message(filters.regex(rf"^{command_prefix_regex}fb(\s+https?://\S+)?$") & (filters.private | filters.group)) 112 | async def fb_handler(client: Client, message: Message): 113 | # Check if user is banned 114 | user_id = message.from_user.id if message.from_user else None 115 | if user_id and banned_users.find_one({"user_id": user_id}): 116 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**", parse_mode=ParseMode.MARKDOWN) 117 | return 118 | 119 | url = None 120 | # Check if URL from reply 121 | if message.reply_to_message and message.reply_to_message.text: 122 | match = re.search(r"https?://(www\.facebook\.com|fb\.watch|m\.facebook\.com)/\S+", message.reply_to_message.text) 123 | if match: 124 | url = match.group(0) 125 | # Check if URL from command 126 | if not url: 127 | command_parts = message.text.split(maxsplit=1) 128 | if len(command_parts) > 1: 129 | match = re.search(r"https?://(www\.facebook\.com|fb\.watch|m\.facebook\.com)/\S+", command_parts[1]) 130 | if match: 131 | url = match.group(0) 132 | 133 | if not url: 134 | await client.send_message( 135 | chat_id=message.chat.id, 136 | text="**Please provide a valid Facebook video link **", 137 | parse_mode=ParseMode.MARKDOWN 138 | ) 139 | logger.warning(f"No Facebook URL provided, user: {user_id or 'unknown'}, chat: {message.chat.id}") 140 | return 141 | 142 | logger.info(f"Facebook URL received: {url}, user: {user_id or 'unknown'}, chat: {message.chat.id}") 143 | downloading_message = await client.send_message( 144 | chat_id=message.chat.id, 145 | text="**Searching The Video**", 146 | parse_mode=ParseMode.MARKDOWN 147 | ) 148 | 149 | try: 150 | video_info = await fb_downloader.download_video(url, downloading_message) 151 | if not video_info: 152 | await downloading_message.edit_text("**Invalid Video URL or Video is Private**", parse_mode=ParseMode.MARKDOWN) 153 | logger.error(f"Failed to download video for URL: {url}") 154 | return 155 | 156 | title = video_info['title'] 157 | filename = video_info['filename'] 158 | webpage_url = video_info['webpage_url'] 159 | 160 | if message.from_user: 161 | user_full_name = f"{message.from_user.first_name} {message.from_user.last_name or ''}".strip() 162 | user_info = f"[{user_full_name}](tg://user?id={user_id})" 163 | else: 164 | group_name = message.chat.title or "this group" 165 | group_url = f"https://t.me/{message.chat.username}" if message.chat.username else "this group" 166 | user_info = f"[{group_name}]({group_url})" 167 | 168 | caption = ( 169 | f"🎥 **Title**: `{title}`\n" 170 | f"━━━━━━━━━━━━━━━━━━━━━\n" 171 | f"🔗 **Link**: [Watch on Facebook]({webpage_url})\n" 172 | f"━━━━━━━━━━━━━━━━━━━━━\n" 173 | f"**Downloaded By**: {user_info}" 174 | ) 175 | 176 | async with aiofiles.open(filename, 'rb'): 177 | start_time = time.time() 178 | last_update_time = [start_time] 179 | await client.send_video( 180 | chat_id=message.chat.id, 181 | video=filename, 182 | supports_streaming=True, 183 | caption=caption, 184 | parse_mode=ParseMode.MARKDOWN, 185 | progress=progress_bar, 186 | progress_args=(downloading_message, start_time, last_update_time) 187 | ) 188 | 189 | await downloading_message.delete() 190 | if os.path.exists(filename): 191 | os.remove(filename) 192 | logger.info(f"Deleted video file: {filename}") 193 | 194 | except Exception as e: 195 | logger.error(f"Error processing Facebook video: {e}") 196 | # Notify admins 197 | await notify_admin(client, f"{COMMAND_PREFIX}fb", e, downloading_message) 198 | # Send user-facing error message 199 | await downloading_message.edit_text("**Facebook Downloader API Dead**", parse_mode=ParseMode.MARKDOWN) -------------------------------------------------------------------------------- /sudoers/sudo/sudo.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import asyncio 5 | from datetime import datetime 6 | from pyrogram import Client, filters 7 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 8 | from pyrogram.enums import ParseMode 9 | from config import OWNER_ID, COMMAND_PREFIX 10 | from core import auth_admins 11 | from utils import LOGGER 12 | from pyrogram.errors import UserIdInvalid, UsernameInvalid, PeerIdInvalid 13 | 14 | def setup_sudo_handler(app: Client): 15 | 16 | async def get_auth_admins(): 17 | """Retrieve all authorized admins from MongoDB.""" 18 | try: 19 | admins = auth_admins.find({}, {"user_id": 1, "title": 1, "auth_date": 1, "_id": 0}) 20 | return {admin["user_id"]: {"title": admin["title"], "auth_date": admin["auth_date"]} for admin in admins} 21 | except Exception as e: 22 | LOGGER.error(f"Error fetching auth admins: {e}") 23 | return {} 24 | 25 | async def add_auth_admin(user_id: int, title: str): 26 | """Add or update an authorized admin in MongoDB with timestamp.""" 27 | try: 28 | auth_admins.update_one( 29 | {"user_id": user_id}, 30 | {"$set": {"user_id": user_id, "title": title, "auth_date": datetime.utcnow()}}, 31 | upsert=True 32 | ) 33 | LOGGER.info(f"Added/Updated admin {user_id} with title {title}") 34 | return True 35 | except Exception as e: 36 | LOGGER.error(f"Error adding/updating admin {user_id}: {e}") 37 | return False 38 | 39 | async def remove_auth_admin(user_id: int): 40 | """Remove an authorized admin from MongoDB.""" 41 | try: 42 | result = auth_admins.delete_one({"user_id": user_id}) 43 | if result.deleted_count > 0: 44 | LOGGER.info(f"Removed admin {user_id}") 45 | return True 46 | else: 47 | LOGGER.info(f"Admin {user_id} not found for removal") 48 | return False 49 | except Exception as e: 50 | LOGGER.error(f"Error removing admin {user_id}: {e}") 51 | return False 52 | 53 | async def resolve_user(client: Client, identifier: str): 54 | """Resolve user by ID or username to get user_id and full name.""" 55 | try: 56 | if identifier.startswith("@"): 57 | user = await client.get_users(identifier) 58 | return user.id, f"{user.first_name} {user.last_name or ''}".strip() 59 | else: 60 | user_id = int(identifier) 61 | user = await client.get_users(user_id) # Verify user exists 62 | return user_id, f"{user.first_name} {user.last_name or ''}".strip() 63 | except (UserIdInvalid, UsernameInvalid, PeerIdInvalid, ValueError) as e: 64 | LOGGER.error(f"Error resolving user {identifier}: {e}") 65 | return None, None 66 | 67 | @app.on_message(filters.command(["getadmins"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 68 | async def get_admins_command(client, message): 69 | user_id = message.from_user.id 70 | if user_id != OWNER_ID: 71 | await client.send_message( 72 | chat_id=message.chat.id, 73 | text="**✘Kids Not Allowed To Do This↯**", 74 | parse_mode=ParseMode.MARKDOWN 75 | ) 76 | return 77 | 78 | loading_message = await client.send_message( 79 | chat_id=message.chat.id, 80 | text="**✘Fetching Admins List↯**", 81 | parse_mode=ParseMode.MARKDOWN 82 | ) 83 | await asyncio.sleep(1) 84 | 85 | admin_list = ["**✘ Bot Admins List ↯**"] 86 | # Add OWNER_ID with title "Owner" 87 | try: 88 | user = await client.get_users(OWNER_ID) 89 | full_name = f"{user.first_name} {user.last_name or ''}".strip() 90 | admin_list.append( 91 | f"\n**✘ Name: {full_name} ↯**\n" 92 | f"**✘ Title: Owner ↯**\n" 93 | f"**✘ Auth Date: Not applicable ↯**" 94 | ) 95 | except Exception: 96 | admin_list.append( 97 | f"\n**✘ Name: ID {OWNER_ID} (Not found) ↯**\n" 98 | f"**✘ Title: Owner ↯**\n" 99 | f"**✘ Auth Date: Not applicable ↯**" 100 | ) 101 | 102 | # Add AUTH_ADMIN_IDS from MongoDB 103 | auth_admins = await get_auth_admins() 104 | for admin_id, data in auth_admins.items(): 105 | try: 106 | user = await client.get_users(admin_id) 107 | full_name = f"{user.first_name} {user.last_name or ''}".strip() 108 | auth_date = data["auth_date"].strftime("%Y-%m-%d %H:%M:%S") 109 | admin_list.append( 110 | f"\n**✘ Name: {full_name} ↯**\n" 111 | f"**✘ Title: {data['title']} ↯**\n" 112 | f"**✘ Auth Date: {auth_date} ↯**" 113 | ) 114 | except Exception: 115 | auth_date = data["auth_date"].strftime("%Y-%m-%d %H:%M:%S") 116 | admin_list.append( 117 | f"\n**✘ Name: ID {admin_id} (Not found) ↯**\n" 118 | f"**✘ Title: {data['title']} ↯**\n" 119 | f"**✘ Auth Date: {auth_date} ↯**" 120 | ) 121 | 122 | if len(admin_list) == 1: 123 | admin_list.append("\nNo additional admins found.") 124 | 125 | await loading_message.edit_text( 126 | text="\n".join(admin_list), 127 | parse_mode=ParseMode.MARKDOWN, 128 | reply_markup=InlineKeyboardMarkup([ 129 | [InlineKeyboardButton("✘ Close ↯", callback_data="close_admins$")] 130 | ]) 131 | ) 132 | 133 | @app.on_message(filters.command(["auth"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 134 | async def auth_command(client, message): 135 | user_id = message.from_user.id 136 | if user_id != OWNER_ID: 137 | await client.send_message( 138 | chat_id=message.chat.id, 139 | text="**✘Kids Not Allowed To Do This↯**", 140 | parse_mode=ParseMode.MARKDOWN 141 | ) 142 | return 143 | 144 | args = message.text.split(maxsplit=2) 145 | if len(args) < 3: 146 | await client.send_message( 147 | chat_id=message.chat.id, 148 | text="**✘Bruh! Provide A Username Or Userid↯**", 149 | parse_mode=ParseMode.MARKDOWN 150 | ) 151 | return 152 | 153 | identifier, title = args[1], args[2] 154 | target_user_id, full_name = await resolve_user(client, identifier) 155 | if not target_user_id: 156 | await client.send_message( 157 | chat_id=message.chat.id, 158 | text="**✘Kids Can't Be Promoted↯**", 159 | parse_mode=ParseMode.MARKDOWN 160 | ) 161 | return 162 | 163 | if target_user_id == OWNER_ID: 164 | await client.send_message( 165 | chat_id=message.chat.id, 166 | text="**✘Cannot Modify Owners Permission↯**", 167 | parse_mode=ParseMode.MARKDOWN 168 | ) 169 | return 170 | 171 | loading_message = await client.send_message( 172 | chat_id=message.chat.id, 173 | text="**✘Adding User To Bot Admins List↯**", 174 | parse_mode=ParseMode.MARKDOWN 175 | ) 176 | await asyncio.sleep(1) 177 | 178 | if await add_auth_admin(target_user_id, title): 179 | await loading_message.edit_text( 180 | text=f"**✘Successfully Authorized User {full_name or identifier} As {title}↯**", 181 | parse_mode=ParseMode.MARKDOWN 182 | ) 183 | else: 184 | await loading_message.edit_text( 185 | text="**✘Kids Can't Be Promoted↯**", 186 | parse_mode=ParseMode.MARKDOWN 187 | ) 188 | 189 | @app.on_message(filters.command(["unauth"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 190 | async def unauth_command(client, message): 191 | user_id = message.from_user.id 192 | if user_id != OWNER_ID: 193 | await client.send_message( 194 | chat_id=message.chat.id, 195 | text="**✘Kids Not Allowed To Do This↯**", 196 | parse_mode=ParseMode.MARKDOWN 197 | ) 198 | return 199 | 200 | args = message.text.split(maxsplit=1) 201 | if len(args) < 2: 202 | await client.send_message( 203 | chat_id=message.chat.id, 204 | text="**✘Bruh! Provide A Username Or Userid↯**", 205 | parse_mode=ParseMode.MARKDOWN 206 | ) 207 | return 208 | 209 | identifier = args[1] 210 | target_user_id, full_name = await resolve_user(client, identifier) 211 | if not target_user_id: 212 | await client.send_message( 213 | chat_id=message.chat.id, 214 | text="**Invalid user ID or username!**", 215 | parse_mode=ParseMode.MARKDOWN 216 | ) 217 | return 218 | 219 | if target_user_id == OWNER_ID: 220 | await client.send_message( 221 | chat_id=message.chat.id, 222 | text="**✘Cannot Modify Owners Permission↯**", 223 | parse_mode=ParseMode.MARKDOWN 224 | ) 225 | return 226 | 227 | loading_message = await client.send_message( 228 | chat_id=message.chat.id, 229 | text="**✘Removing User From Bot Admins List↯**", # Fixed typo 230 | parse_mode=ParseMode.MARKDOWN 231 | ) 232 | await asyncio.sleep(1) 233 | 234 | if await remove_auth_admin(target_user_id): 235 | await loading_message.edit_text( 236 | text=f"**✘Successfully Removed User {full_name or identifier} From Admins↯**", 237 | parse_mode=ParseMode.MARKDOWN 238 | ) 239 | else: 240 | await loading_message.edit_text( 241 | text=f"**✘The User Is Not In Admin List↯**", 242 | parse_mode=ParseMode.MARKDOWN 243 | ) 244 | 245 | @app.on_callback_query(filters.regex(r"^close_admins\$")) 246 | async def handle_close_callback(client: Client, query: CallbackQuery): 247 | user_id = query.from_user.id 248 | if user_id != OWNER_ID: 249 | await query.answer( 250 | text="✘Kids Not Allowed To Do This↯", 251 | show_alert=True 252 | ) 253 | return 254 | await query.message.delete() 255 | await query.answer() 256 | -------------------------------------------------------------------------------- /sudoers/logs/logs.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import asyncio 6 | from pyrogram import Client, filters 7 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 8 | from pyrogram.enums import ParseMode 9 | from utils import LOGGER 10 | from config import OWNER_ID, COMMAND_PREFIX 11 | from core import auth_admins 12 | from telegraph import Telegraph 13 | 14 | # Initialize Telegraph client 15 | telegraph = Telegraph() 16 | telegraph.create_account( 17 | short_name="SmartUtilBot", 18 | author_name="SmartUtilBot", 19 | author_url="https://t.me/TheSmartDevs" 20 | ) 21 | 22 | def setup_logs_handler(app: Client): 23 | 24 | async def create_telegraph_page(content: str) -> list: 25 | """Create Telegraph pages with the given content, each under 20 KB, and return list of URLs""" 26 | try: 27 | # Truncate content to 40,000 characters to respect Telegraph character limits 28 | truncated_content = content[:40000] 29 | # Convert content to bytes to measure size accurately 30 | content_bytes = truncated_content.encode('utf-8') 31 | max_size_bytes = 20 * 1024 # 20 KB in bytes 32 | pages = [] 33 | page_content = "" 34 | current_size = 0 35 | lines = truncated_content.splitlines(keepends=True) 36 | 37 | for line in lines: 38 | line_bytes = line.encode('utf-8') 39 | # Check if adding this line would exceed 20 KB 40 | if current_size + len(line_bytes) > max_size_bytes and page_content: 41 | # Create a Telegraph page with the current content 42 | response = telegraph.create_page( 43 | title="SmartLogs", 44 | html_content=f"
{page_content}
", 45 | author_name="SmartUtilBot", 46 | author_url="https://t.me/TheSmartDevs" 47 | ) 48 | pages.append(f"https://telegra.ph/{response['path']}") 49 | # Reset for the next page 50 | page_content = "" 51 | current_size = 0 52 | page_content += line 53 | current_size += len(line_bytes) 54 | 55 | # Create a page for any remaining content 56 | if page_content: 57 | response = telegraph.create_page( 58 | title="SmartLogs", 59 | html_content=f"
{page_content}
", 60 | author_name="SmartUtilBot", 61 | author_url="https://t.me/TheSmartDevs" 62 | ) 63 | pages.append(f"https://telegra.ph/{response['path']}") 64 | 65 | return pages 66 | except Exception as e: 67 | LOGGER.error(f"Failed to create Telegraph page: {e}") 68 | return [] 69 | 70 | @app.on_message(filters.command(["logs"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 71 | async def logs_command(client, message): 72 | user_id = message.from_user.id 73 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 74 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 75 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 76 | LOGGER.info("User not admin or owner, sending restricted message") 77 | await client.send_message( 78 | chat_id=message.chat.id, 79 | text="**✘Kids Not Allowed To Do This↯**", 80 | parse_mode=ParseMode.MARKDOWN 81 | ) 82 | return 83 | 84 | # Send a loading message 85 | loading_message = await client.send_message( 86 | chat_id=message.chat.id, 87 | text="**Checking The Logs...💥**", 88 | parse_mode=ParseMode.MARKDOWN 89 | ) 90 | 91 | # Wait for 2 seconds 92 | await asyncio.sleep(2) 93 | 94 | # Check if logs exist 95 | if not os.path.exists("botlog.txt"): 96 | await loading_message.edit_text( 97 | text="**Sorry Bro No Logs Found**", 98 | parse_mode=ParseMode.MARKDOWN 99 | ) 100 | return 101 | 102 | LOGGER.info("User is admin or owner, sending log document") 103 | await client.send_document( 104 | chat_id=message.chat.id, 105 | document="botlog.txt", 106 | caption="""**✘ Hey Sir! Here Is Your Logs ↯** 107 | **✘━━━━━━━━━━━━━━━━━━━━━━━━━↯** 108 | **✘ All Logs Database Succesfully Exported! ↯** 109 | **↯ Access Granted Only to Authorized Admins ↯** 110 | **✘━━━━━━━━━━━━━━━━━━━━━━━━━↯** 111 | **✘ Select an Option Below to View Logs:** 112 | **✘ Logs Here Offer the Fastest and Clearest Access! ↯** 113 | **✘━━━━━━━━━━━━━━━━━━━━━━━━━↯** 114 | **✘Huge Respect For You My Master↯**""", 115 | parse_mode=ParseMode.MARKDOWN, 116 | reply_markup=InlineKeyboardMarkup([ 117 | [ 118 | InlineKeyboardButton("✘ Display Logs↯", callback_data="display_logs"), 119 | InlineKeyboardButton("✘ Web Paste↯", callback_data="web_paste$") 120 | ], 121 | [InlineKeyboardButton("✘ Close↯", callback_data="close_doc$")] 122 | ]) 123 | ) 124 | 125 | # Delete the temporary "Checking The Logs..." message 126 | await loading_message.delete() 127 | 128 | @app.on_callback_query(filters.regex(r"^(close_doc\$|close_logs\$|web_paste\$|display_logs)$")) 129 | async def handle_callback(client: Client, query: CallbackQuery): 130 | user_id = query.from_user.id 131 | data = query.data 132 | LOGGER.info(f"Callback query from user {user_id}, data: {data}") 133 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 134 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 135 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 136 | LOGGER.info("User not admin or owner, sending callback answer") 137 | await query.answer( 138 | text="✘Kids Not Allowed To Do This↯", 139 | show_alert=True 140 | ) 141 | return 142 | LOGGER.info("User is admin or owner, processing callback") 143 | if data == "close_doc$": 144 | await query.message.delete() 145 | await query.answer() 146 | elif data == "close_logs$": 147 | await query.message.delete() 148 | await query.answer() 149 | elif data == "web_paste$": 150 | await query.answer("Uploading logs to Telegraph...") 151 | # Edit the main log message to show uploading status 152 | await query.message.edit_caption( 153 | caption="**✘Uploading SmartLogs To Telegraph↯**", 154 | parse_mode=ParseMode.MARKDOWN 155 | ) 156 | # Check if logs exist 157 | if not os.path.exists("botlog.txt"): 158 | await query.message.edit_caption( 159 | caption="**✘Sorry Bro Telegraph API Dead↯**", 160 | parse_mode=ParseMode.MARKDOWN 161 | ) 162 | return 163 | try: 164 | # Read and truncate logs 165 | with open("botlog.txt", "r", encoding="utf-8") as f: 166 | logs_content = f.read() 167 | # Create Telegraph pages 168 | telegraph_urls = await create_telegraph_page(logs_content) 169 | if telegraph_urls: 170 | # Create buttons with two per row 171 | buttons = [] 172 | for i in range(0, len(telegraph_urls), 2): 173 | row = [ 174 | InlineKeyboardButton(f"✘ View Web Part {i+1}↯", url=telegraph_urls[i]) 175 | ] 176 | if i + 1 < len(telegraph_urls): 177 | row.append(InlineKeyboardButton(f"✘ View Web Part {i+2}↯", url=telegraph_urls[i+1])) 178 | buttons.append(row) 179 | # Add a close button in its own row 180 | buttons.append([InlineKeyboardButton("✘ Close↯", callback_data="close_doc$")]) 181 | await query.message.edit_caption( 182 | caption="""**✘ Hey Sir! Here Is Your Logs ↯** 183 | **✘━━━━━━━━━━━━━━━━━━━━━━━━━↯** 184 | **✘ All Logs Database Succesfully Exported! ↯** 185 | **↯ Access Granted Only to Authorized Admins ↯** 186 | **✘━━━━━━━━━━━━━━━━━━━━━━━━━↯** 187 | **✘ Select a Page Below to View Logs:** 188 | **✘ Logs Here Offer the Fastest and Clearest Access! ↯** 189 | **✘━━━━━━━━━━━━━━━━━━━━━━━━━↯** 190 | **✘Huge Respect For You My Master↯**""", 191 | parse_mode=ParseMode.MARKDOWN, 192 | reply_markup=InlineKeyboardMarkup(buttons) 193 | ) 194 | else: 195 | await query.message.edit_caption( 196 | caption="**✘Sorry Bro Telegraph API Dead↯**", 197 | parse_mode=ParseMode.MARKDOWN 198 | ) 199 | except Exception as e: 200 | LOGGER.error(f"Error uploading to Telegraph: {e}") 201 | await query.message.edit_caption( 202 | caption="**✘Sorry Bro Telegraph API Dead↯**", 203 | parse_mode=ParseMode.MARKDOWN 204 | ) 205 | elif data == "display_logs": 206 | await send_logs_page(client, query.message.chat.id) 207 | await query.answer() 208 | 209 | async def send_logs_page(client: Client, chat_id: int): 210 | """Send the last 20 lines of botlog.txt, respecting Telegram's 4096-character limit""" 211 | LOGGER.info(f"Sending latest logs to chat {chat_id}") 212 | if not os.path.exists("botlog.txt"): 213 | await client.send_message( 214 | chat_id=chat_id, 215 | text="**✘Sorry Bro No Logs Found↯**", 216 | parse_mode=ParseMode.MARKDOWN 217 | ) 218 | return 219 | try: 220 | with open("botlog.txt", "r", encoding="utf-8") as f: 221 | logs = f.readlines() 222 | # Get the last 20 lines (or fewer if the file is shorter) 223 | latest_logs = logs[-20:] if len(logs) > 20 else logs 224 | text = "".join(latest_logs) 225 | # Truncate to 4096 characters (Telegram's message limit) 226 | if len(text) > 4096: 227 | text = text[-4096:] 228 | await client.send_message( 229 | chat_id=chat_id, 230 | text=text if text else "No logs available.", 231 | parse_mode=ParseMode.DISABLED, 232 | reply_markup=InlineKeyboardMarkup([ 233 | [InlineKeyboardButton("✘ Back↯", callback_data="close_logs$")] 234 | ]) 235 | ) 236 | except Exception as e: 237 | LOGGER.error(f"Error sending logs: {e}") 238 | await client.send_message( 239 | chat_id=chat_id, 240 | text="**✘Sorry There Was A Issue On My Server↯**", 241 | parse_mode=ParseMode.MARKDOWN 242 | ) 243 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SecureXTools Bot 🚀 2 | 3 | ![GitHub repo size](https://img.shields.io/github/repo-size/TheSmartDevs/SecureXTools) 4 | ![GitHub license](https://img.shields.io/github/license/TheSmartDevs/SecureXTools) 5 | ![GitHub issues](https://img.shields.io/github/issues/TheSmartDevs/SecureXTools) 6 | ![GitHub stars](https://img.shields.io/github/stars/TheSmartDevs/SecureXTools?style=social) 7 | ![Telegram](https://img.shields.io/badge/Telegram-Join%20Channel-blue?logo=telegram) 8 | 9 | SecureXTools is a powerful, feature-rich Telegram bot designed to provide tools for media downloading, IP and proxy checking, website screenshots, and administrative controls. It supports deployment on multiple platforms, including VPS, Heroku, and Docker, with compatibility for Ubuntu, Windows, RDP, and Debian hosting. 10 | 11 | **Project Owner:** [@ISmartDevs](https://t.me/ISmartDevs) 12 | **Repository:** [GitHub - SecureXTools](https://github.com/TheSmartDevs/SecureXTools) 13 | **Community:** Join our [Telegram Channel](https://t.me/TheSmartDev) for updates and support 📢. 14 | 15 | ## Features ✨ Of SecureXTools 16 | 17 | SecureXTools Bot offers the following commands and functionalities: 18 | 19 | - **/start**: Initialize the SecureXTools Bot. 20 | - **/help**: Display the help menu and list of available commands. 21 | - **/info**: Retrieve user information from the database. 22 | - **/id**: Get group or channel information. 23 | - **/ip**: Fetch details about any IP address. 24 | - **/px**: Check proxies of any type (up to a limit of 20). 25 | - **/ss**: Capture a screenshot of any website. 26 | - **/fb**: Download videos from Facebook. 27 | - **/in**: Download Instagram reels and posts. 28 | - **/sp**: Download tracks from Spotify. 29 | - **/song**: Download music from YouTube. 30 | - **/video**: Download videos from YouTube. 31 | - **/tt**: Download TikTok videos. 32 | - **/pnt**: Download Pinterest videos. 33 | - **/settings**: Modify bot variables (Admin only). 34 | - **/auth**: Promote a user to sudo status (Admin only). 35 | - **/unauth**: Demote a user from sudo status (Admin only). 36 | - **/gban**: Ban a user from using the bot (Admin only). 37 | - **/gunban**: Unban a user from using the bot (Admin only). 38 | - **/logs**: Retrieve bot console logs (Admin only). 39 | - **/restart**: Restart the bot (Admin only). 40 | - **/speedtest**: Check the bot server’s speed (Admin only). 41 | - **/send**: Broadcast messages to users (Admin only). 42 | - **/stats**: View bot usage statistics (Admin only). 43 | - **/broadcast**: Broadcast messages to users using (Admin only). 44 | - **/stats**: View bot usage statistics (Admin only). 45 | - **/off**: Turn Entire Bot Off (Admin only). 46 | 47 | 48 | ## Prerequisites 🛠️ For SecureXTools Bot 49 | 50 | Before deploying SecureXTools Bot, ensure the following dependencies are installed: 51 | 52 | 1. **Python 3.8+**: Required for running the bot. 53 | 2. **FFmpeg**: Necessary for media processing. 54 | - For Ubuntu/Debian: 55 | ```bash 56 | sudo apt update 57 | sudo apt install ffmpeg 58 | ``` 59 | - Note: FFmpeg cannot be installed via `pip`. Use your system’s package manager. 60 | 3. **Python Dependencies**: 61 | - Install required Python packages: 62 | ```bash 63 | pip3 install -r requirements.txt 64 | ``` 65 | 66 | ## Environment Variables ⚙️ 67 | 68 | ### Mandatory Variables For Bot Deployment 69 | The following environment variables must be set for the bot to function correctly: 70 | 71 | | Variable | Description | Example Value | 72 | |----------------------|--------------------------------------------------|----------------------------------------------| 73 | | `API_ID` | Telegram API ID from [my.telegram.org](https://my.telegram.org). | Your_API_ID_Here | 74 | | `API_HASH` | Telegram API Hash from [my.telegram.org](https://my.telegram.org). | Your_API_HASH_Here | 75 | | `BOT_TOKEN` | Bot token from [@BotFather](https://t.me/BotFather). | Your_BOT_TOKEN_Here | 76 | | `BOT_USERNAME` | Bot’s Telegram username. | @YourBotUsername | 77 | | `BOT_NAME` | Bot’s display name. | YourBotName | 78 | | `OWNER_ID` | Telegram ID of the bot owner. | Your_OWNER_ID_Here | 79 | | `DEVELOPER_USER_ID` | Telegram ID of the developer (usually same as OWNER_ID). | Your_DEVELOPER_USER_ID_Here | 80 | | `MONGO_URL` | MongoDB connection URL. | Your_MONGO_URL_Here | 81 | | `DATABASE_URL` | Same as `MONGO_URL` for database operations. | Your_DATABASE_URL_Here | 82 | 83 | ### Optional Variables For Proper Working.. 84 | The following variables are optional and have default values if not set: 85 | 86 | | Variable | Description | Default Value | 87 | |----------------------|--------------------------------------------------|----------------------------------------------| 88 | | `COMMAND_PREFIX` | Prefixes for bot commands. | `!|.|#|,|/` | 89 | | `UPDATE_CHANNEL_URL` | Telegram channel for updates. | `https://t.me/TheSmartDev` | 90 | | `IMGAI_SIZE_LIMIT` | Max file size for image AI tools (bytes). | `5242880` | 91 | | `MAX_TXT_SIZE` | Max text file size (bytes). | `15728640` | 92 | | `MAX_VIDEO_SIZE` | Max video file size (bytes). | `2147483648` | 93 | | `YT_COOKIES_PATH` | Path to YouTube cookies file. | `./cookies/SecureXTools.txt` | 94 | | `VIDEO_RESOLUTION` | Resolution for YouTube downloads. | `1280x720` | 95 | | `PROXY_CHECK_LIMIT` | Max number of proxies to check. | `20` | 96 | 97 | ## Deployment Methods & Instructions 98 | 99 | SecureXTools Bot supports multiple deployment methods: VPS, Heroku, and Docker. Follow the instructions below for your preferred platform. 100 | 101 | ### 1. Deploying on a VPS with Screen 102 | 103 | #### Install Screen 104 | Screen allows you to run the bot in a persistent session, even after closing your terminal. 105 | 106 | - For Ubuntu/Debian: 107 | ```bash 108 | sudo apt update 109 | sudo apt install screen 110 | ``` 111 | 112 | - Start a new screen session: 113 | ```bash 114 | screen -S SecureXTools 115 | ``` 116 | 117 | #### Deploy the Bot 118 | 1. Clone the repository: 119 | ```bash 120 | git clone https://github.com/TheSmartDevs/SecureXTools.git 121 | cd SecureXTools 122 | ``` 123 | 124 | 2. Install dependencies: 125 | ```bash 126 | sudo apt install ffmpeg 127 | pip3 install -r requirements.txt 128 | ``` 129 | 130 | 3. Set up environment variables: 131 | - Create a `.env` file in the project root and populate it with the variables listed above. 132 | - Alternatively, edit `config.py` directly with your values Or `cp sample.env .env` 133 | 134 | 4. Run the bot: 135 | ```bash 136 | python3 main.py 137 | ``` 138 | 139 | 5. Detach from the screen session: 140 | - Press `Ctrl+A`, then `Ctrl+D` to detach. 141 | - To reattach later: 142 | ```bash 143 | screen -r SecureXTools 144 | ``` 145 | 146 | 6. Stop the bot: 147 | - Reattach to the screen session (`screen -r SecureXTools`). 148 | - Press `Ctrl+C` to stop the bot. 149 | 150 | ### 2. Heroku Deploy Methods!!! 151 | 152 | #### Deploy with Heroku Button 153 | For a quick deployment, use the Heroku Deploy button: 154 | 155 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/TheSmartDevs/SecureXTools) 156 | 157 | #### Manual Heroku Deployment For Professionals 158 | 1. Clone the repository: 159 | ```bash 160 | git clone https://github.com/TheSmartDevs/SecureXTools.git 161 | cd SecureXTools 162 | ``` 163 | 164 | 2. Create a Heroku app: 165 | ```bash 166 | heroku create your-app-name 167 | ``` 168 | 169 | 3. Set environment variables: 170 | - Use the Heroku dashboard or CLI to set the required variables: 171 | ```bash 172 | heroku config:set API_ID=Your_API_ID_Here 173 | heroku config:set API_HASH=Your_API_HASH_Here 174 | heroku config:set BOT_TOKEN=Your_BOT_TOKEN_Here 175 | # Add other variables as needed 176 | ``` 177 | 178 | 4. Deploy the app: 179 | ```bash 180 | git push heroku main 181 | ``` 182 | 183 | 5. Start the bot: 184 | ```bash 185 | heroku ps:scale worker=1 186 | ``` 187 | 188 | 6. Install FFmpeg on Heroku: 189 | - Add the FFmpeg buildpack: 190 | ```bash 191 | heroku buildpacks:add https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git 192 | ``` 193 | 194 | ### 3. Deploying with Docker Compose Method 195 | 196 | #### Prerequisites 197 | - Install [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/). 198 | 199 | #### Deploy with Docker Compose 200 | 1. Clone the repository: 201 | ```bash 202 | git clone https://github.com/TheSmartDevs/SecureXTools.git 203 | cd SecureXTools 204 | ``` 205 | 206 | 2. Create a `.env` file in the project root with the required environment variables. 207 | 208 | 3. Build and run the bot: 209 | ```bash 210 | docker compose up --build --remove-orphans 211 | ``` 212 | 213 | 4. Stop the bot: 214 | ```bash 215 | docker compose down 216 | ``` 217 | 218 | ## Bot Father Commands Setup Easy Method 219 | 220 | 1. **First Open Bot Father**: 221 | - First Go To [@BotFather](https://t.me/BotFather) Then Paste The Commands By Coping From Cutting From `cmds.txt` File. 222 | 2. **Easiest Way With Sudo Mode**: 223 | - Just Send /set Command To Your Hosted Bot And Then Commands Will Auto Set If You Are Owner Of The Bot Or Your UserID Is In `OWNER_ID` VAR. 224 | 225 | ## Handling YouTube Download Errors with Cookies 📄 226 | 227 | To avoid YouTube sign-in or bot protection errors, use a cookie file for authentication. Follow these steps: 228 | 229 | 1. **Create a Dedicated Chrome Profile**: 230 | - Set up a new Chrome profile for the bot to manage cookies securely. 231 | 232 | 2. **Install a Cookie Management Extension**: 233 | - Use an extension like [Cookie Editor](https://chrome.google.com/webstore/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm) to export cookies. 234 | 235 | 3. **Export Cookies from YouTube**: 236 | - Log into YouTube using the dedicated Chrome profile. 237 | - Use the cookie extension to export cookies in Netscape format. 238 | 239 | 4. **Save the Cookies File**: 240 | - Save the exported cookies as `SecureXTools.txt` in the `./cookies/SecureXTools.txt` directory. 241 | 242 | ### Cookie Management Tips 243 | - **Cookie Expiry**: YouTube cookies may expire. If downloads fail, export and replace the cookies file. 244 | - **Avoid Cookie Depletion**: 245 | - Do not play YouTube videos on the account used for cookies. 246 | - Avoid signing out from the associated Gmail account on your device. 247 | - Minimize frequent bot restarts to prevent cookie invalidation. 248 | - **Monitor Cookies**: Regularly check bot activity to ensure cookies remain valid. 249 | 250 | This setup ensures reliable access to YouTube content without sign-in or bot protection errors. 251 | 252 | ## Contributing 🤝 To SecureXTools 253 | 254 | We welcome contributions to improve SecureXTools Bot. To contribute: 255 | 1. Fork the repository. 256 | 2. Create a new branch for your feature or bug fix. 257 | 3. Submit a pull request with a clear description of your changes. 258 | 259 | Please ensure your code follows the project’s coding standards and includes appropriate documentation. 260 | 261 | ## Support 📞 For Any Issue 262 | 263 | For issues, questions, or feature requests: 264 | - Join our [Telegram Channel](https://t.me/TheSmartDev) for community support. 265 | - Contact the project owner: [@ISmartDevs](https://t.me/ISmartDevs). 266 | - Open an issue on the [GitHub repository](https://github.com/TheSmartDevs/SecureXTools). 267 | 268 | ## License 📝 269 | 270 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 271 | 272 | SecureXTools Bot is a project by [@ISmartDevs](https://t.me/ISmartDevs). Built for the Telegram community. 273 | 274 | ## Ethical Notice 📜 275 | 276 | Simply modifying a few lines of code does not constitute original authorship. When forking this project, always: 277 | - Fork responsibly and give proper credit to the original creators (@ISmartDevs). 278 | - Customize the code as needed, but do not claim it as your own without significant contributions. -------------------------------------------------------------------------------- /sudoers/settings/settings.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | from pyrogram import Client, filters 5 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message, CallbackQuery 6 | from pyrogram.enums import ParseMode, ChatType 7 | from pyrogram.handlers import MessageHandler, CallbackQueryHandler 8 | import os 9 | from dotenv import load_dotenv 10 | from config import COMMAND_PREFIX, OWNER_ID 11 | from core import auth_admins 12 | from utils import LOGGER 13 | 14 | # Load The Environment Variables 15 | load_dotenv() 16 | 17 | # Temp Session Storage 18 | user_session = {} 19 | 20 | def validate_message(func): 21 | async def wrapper(client: Client, message: Message): 22 | if not message or not message.from_user: 23 | LOGGER.error("Invalid message received") 24 | return 25 | return await func(client, message) 26 | return wrapper 27 | 28 | def admin_only(func): 29 | async def wrapper(client: Client, message: Message): 30 | user_id = message.from_user.id 31 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 32 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 33 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 34 | LOGGER.info(f"Unauthorized settings access attempt by user_id {user_id}") 35 | await client.send_message( 36 | chat_id=message.chat.id, 37 | text="**🚫 Hey Gay 🏳️‍🌈 This Is Not For You This Only For Males👱‍♂️**", 38 | parse_mode=ParseMode.MARKDOWN 39 | ) 40 | return 41 | return await func(client, message) 42 | return wrapper 43 | 44 | # Helper Functions 45 | def detect_duplicate_keys(): 46 | """Log a warning for duplicate keys in the .env file.""" 47 | try: 48 | with open(".env") as f: 49 | lines = f.readlines() 50 | seen_keys = set() 51 | duplicates = set() 52 | for line in lines: 53 | if '=' in line: 54 | key = line.split("=", 1)[0].strip() 55 | if key in seen_keys: 56 | duplicates.add(key) 57 | seen_keys.add(key) 58 | if duplicates: 59 | LOGGER.warning(f"Duplicate keys found in .env: {', '.join(duplicates)}") 60 | except Exception as e: 61 | LOGGER.error(f"Error detecting duplicate keys in .env: {e}") 62 | 63 | def load_env_vars(): 64 | """Load all unique environment variables from the .env file.""" 65 | try: 66 | with open(".env") as f: 67 | lines = f.readlines() 68 | variables = {} 69 | seen_keys = set() 70 | for line in lines: 71 | if '=' in line: 72 | key, value = line.split("=", 1) 73 | key = key.strip() 74 | value = value.strip() 75 | if key not in seen_keys: 76 | variables[key] = value 77 | seen_keys.add(key) 78 | LOGGER.info("Environment variables loaded successfully") 79 | return variables 80 | except Exception as e: 81 | LOGGER.error(f"Error loading environment variables: {e}") 82 | return {} 83 | 84 | def update_env_var(key, value): 85 | """Update a specific environment variable in the .env file.""" 86 | try: 87 | env_vars = load_env_vars() 88 | env_vars[key] = value 89 | with open(".env", "w") as f: 90 | for k, v in env_vars.items(): 91 | f.write(f"{k}={v}\n") 92 | LOGGER.info(f"Updated environment variable: {key}") 93 | except Exception as e: 94 | LOGGER.error(f"Error updating environment variable {key}: {e}") 95 | 96 | # Initialize config 97 | detect_duplicate_keys() 98 | config_keys = load_env_vars() 99 | ITEMS_PER_PAGE = 10 100 | 101 | def build_menu(page=0): 102 | """Build the inline keyboard menu for settings.""" 103 | keys = list(config_keys.keys()) 104 | start, end = page * ITEMS_PER_PAGE, (page + 1) * ITEMS_PER_PAGE 105 | current_keys = keys[start:end] 106 | 107 | rows = [] 108 | for i in range(0, len(current_keys), 2): 109 | buttons = [ 110 | InlineKeyboardButton(current_keys[i], callback_data=f"settings_edit_{current_keys[i]}") 111 | ] 112 | if i + 1 < len(current_keys): 113 | buttons.append(InlineKeyboardButton(current_keys[i + 1], callback_data=f"settings_edit_{current_keys[i + 1]}")) 114 | rows.append(buttons) 115 | 116 | nav_buttons = [] 117 | if page > 0: 118 | nav_buttons.append(InlineKeyboardButton("⬅️ Previous", callback_data=f"settings_page_{page - 1}")) 119 | if end < len(keys): 120 | nav_buttons.append(InlineKeyboardButton("Next ➡️", callback_data=f"settings_page_{page + 1}")) 121 | if nav_buttons: 122 | if page == 0: 123 | nav_buttons.append(InlineKeyboardButton("Close ❌", callback_data="settings_closesettings")) 124 | rows.append(nav_buttons) 125 | else: 126 | rows.append(nav_buttons) 127 | 128 | if page > 0: 129 | rows.append([InlineKeyboardButton("Close ❌", callback_data="settings_closesettings")]) 130 | 131 | return InlineKeyboardMarkup(rows) 132 | 133 | def setup_settings_handler(app: Client): 134 | """Setup the settings handler for the Pyrogram app.""" 135 | 136 | @validate_message 137 | async def debug_all(client: Client, message: Message): 138 | """Catch-all handler to debug all group chat messages.""" 139 | thread_id = getattr(message, "message_thread_id", None) 140 | is_reply = message.reply_to_message_id is not None 141 | message_text = message.text or message.caption or "[no text]" 142 | 143 | LOGGER.debug( 144 | f"Catch-all: user {message.from_user.id}, chat {message.chat.id}, " 145 | f"text='{message_text[:50]}', chat_type={message.chat.type}, " 146 | f"is_reply={is_reply}, reply_to={message.reply_to_message_id}, " 147 | f"thread={thread_id}" 148 | ) 149 | 150 | @validate_message 151 | @admin_only 152 | async def show_settings(client: Client, message: Message): 153 | """Show the settings menu.""" 154 | LOGGER.info(f"Settings command initiated by user_id {message.from_user.id}") 155 | if message.chat.type in [ChatType.GROUP, ChatType.SUPERGROUP]: 156 | try: 157 | chat = await client.get_chat(message.chat.id) 158 | if not chat.permissions.can_send_messages: 159 | await client.send_message( 160 | chat_id=message.chat.id, 161 | text="**Sorry Bro This Group Is Restricted**", 162 | parse_mode=ParseMode.MARKDOWN 163 | ) 164 | return 165 | except Exception as e: 166 | LOGGER.error(f"Failed to check permissions: {e}") 167 | return 168 | 169 | await client.send_message( 170 | chat_id=message.chat.id, 171 | text="**Select a change or edit 👇**", 172 | parse_mode=ParseMode.MARKDOWN, 173 | reply_markup=build_menu() 174 | ) 175 | 176 | async def paginate_menu(client: Client, callback_query: CallbackQuery): 177 | """Handle pagination in the settings menu.""" 178 | user_id = callback_query.from_user.id 179 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 180 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 181 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 182 | LOGGER.info(f"Unauthorized pagination attempt by user_id {user_id}") 183 | await callback_query.answer("🚫 Hey Gay 🏳️‍🌈 This Is Not For You This Only For Males👱‍♂️", show_alert=True) 184 | return 185 | 186 | page = int(callback_query.data.split("_")[2]) 187 | await callback_query.edit_message_reply_markup(reply_markup=build_menu(page)) 188 | await callback_query.answer() 189 | LOGGER.debug(f"Paginated to page {page} by user_id {user_id}") 190 | 191 | async def edit_var(client: Client, callback_query: CallbackQuery): 192 | """Handle the selection of a variable to edit.""" 193 | user_id = callback_query.from_user.id 194 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 195 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 196 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 197 | LOGGER.info(f"Unauthorized edit attempt by user_id {user_id}") 198 | await callback_query.answer("🚫 Hey Gay 🏳️‍🌈 This Is Not For You This Only For Males👱‍♂️", show_alert=True) 199 | return 200 | 201 | var_name = callback_query.data.split("_", 2)[2] 202 | if var_name not in config_keys: 203 | await callback_query.answer("Invalid variable selected.", show_alert=True) 204 | LOGGER.warning(f"Invalid variable {var_name} selected by user_id {user_id}") 205 | return 206 | 207 | user_session[user_id] = { 208 | "var": var_name, 209 | "chat_id": callback_query.message.chat.id 210 | } 211 | 212 | await callback_query.edit_message_text( 213 | text=f"**Editing `{var_name}`. Please send the new value below.**", 214 | parse_mode=ParseMode.MARKDOWN, 215 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Cancel ❌", callback_data="settings_cancel_edit")]]) 216 | ) 217 | LOGGER.info(f"User_id {user_id} started editing variable {var_name}") 218 | 219 | async def cancel_edit(client: Client, callback_query: CallbackQuery): 220 | """Cancel the editing process.""" 221 | user_id = callback_query.from_user.id 222 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 223 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 224 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 225 | LOGGER.info(f"Unauthorized cancel edit attempt by user_id {user_id}") 226 | await callback_query.answer("🚫 Hey Gay 🏳️‍🌈 This Is Not For You This Only For Males👱‍♂️", show_alert=True) 227 | return 228 | 229 | user_session.pop(user_id, None) 230 | await callback_query.edit_message_text("**Variable Editing Cancelled**", parse_mode=ParseMode.MARKDOWN) 231 | await callback_query.answer() 232 | LOGGER.info(f"User_id {user_id} cancelled variable editing") 233 | 234 | @validate_message 235 | async def update_value(client: Client, message: Message): 236 | """Update the value of a selected variable.""" 237 | user_id = message.from_user.id 238 | session = user_session.get(user_id) 239 | if not session: 240 | return 241 | 242 | message_text = message.text or message.caption 243 | if not message_text: 244 | await client.send_message( 245 | chat_id=message.chat.id, 246 | text="**Please provide a text value to update.**", 247 | parse_mode=ParseMode.MARKDOWN 248 | ) 249 | return 250 | 251 | var, val = session["var"], message_text.strip() 252 | update_env_var(var, val) 253 | config_keys[var] = val 254 | 255 | await client.send_message( 256 | chat_id=message.chat.id, 257 | text=f"**`{var}` Has Been Successfully Updated To `{val}`. ✅**", 258 | parse_mode=ParseMode.MARKDOWN 259 | ) 260 | 261 | user_session.pop(user_id, None) 262 | load_dotenv(override=True) 263 | LOGGER.info(f"User_id {user_id} updated variable {var} to {val}") 264 | 265 | async def close_menu(client: Client, callback_query: CallbackQuery): 266 | """Close the settings menu.""" 267 | user_id = callback_query.from_user.id 268 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 269 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 270 | if user_id != OWNER_ID and user_id not in AUTH_ADMIN_IDS: 271 | LOGGER.info(f"Unauthorized close menu attempt by user_id {user_id}") 272 | await callback_query.answer("🚫 Hey Gay 🏳️‍🌈 This Is Not For You This Only For Males👱‍♂️", show_alert=True) 273 | return 274 | 275 | await callback_query.edit_message_text("**Settings Menu Closed Successfully ✅**", parse_mode=ParseMode.MARKDOWN) 276 | await callback_query.answer() 277 | LOGGER.info(f"User_id {user_id} closed settings menu") 278 | 279 | # Register handlers 280 | app.add_handler(MessageHandler(debug_all, filters.chat([ChatType.GROUP, ChatType.SUPERGROUP])), group=1) 281 | app.add_handler(MessageHandler(show_settings, filters.command(["settings"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)), group=1) 282 | app.add_handler(MessageHandler(update_value, filters.text), group=1) 283 | app.add_handler(CallbackQueryHandler(paginate_menu, filters.regex(r"^settings_page_(\d+)$")), group=1) 284 | app.add_handler(CallbackQueryHandler(edit_var, filters.regex(r"^settings_edit_(.+)")), group=1) 285 | app.add_handler(CallbackQueryHandler(cancel_edit, filters.regex(r"^settings_cancel_edit$")), group=1) 286 | app.add_handler(CallbackQueryHandler(close_menu, filters.regex(r"^settings_closesettings$")), group=1) 287 | -------------------------------------------------------------------------------- /modules/dlxutils/insta.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import re 6 | import time 7 | import asyncio 8 | import aiohttp 9 | import aiofiles 10 | from pathlib import Path 11 | from typing import Optional, List 12 | from pyrogram import Client, filters 13 | from pyrogram.types import Message, InputMediaPhoto, InputMediaVideo, InlineKeyboardMarkup, InlineKeyboardButton 14 | from pyrogram.enums import ParseMode 15 | from config import COMMAND_PREFIX 16 | from utils import LOGGER, progress_bar, notify_admin # Import LOGGER, progress_bar, and notify_admin from utils 17 | from core import banned_users # Check if user is banned 18 | 19 | # Configuration 20 | class Config: 21 | TEMP_DIR = Path("temp") 22 | MAX_MEDIA_PER_GROUP = 10 # Telegram's media group limit 23 | 24 | Config.TEMP_DIR.mkdir(exist_ok=True) 25 | 26 | class InstagramDownloader: 27 | def __init__(self, temp_dir: Path): 28 | self.temp_dir = temp_dir 29 | 30 | async def sanitize_filename(self, username: str, shortcode: str, index: int, media_type: str) -> str: 31 | """Sanitize file name using username, shortcode, and index.""" 32 | safe_username = re.sub(r'[<>:"/\\|?*]', '', username[:30]).strip() 33 | safe_shortcode = re.sub(r'[<>:"/\\|?*]', '', shortcode).strip() 34 | return f"{safe_username}_{safe_shortcode}_{index}_{int(time.time())}.{ 'mp4' if media_type == 'video' else 'jpg' }" 35 | 36 | async def download_content(self, url: str, downloading_message: Message, content_type: str) -> Optional[dict]: 37 | self.temp_dir.mkdir(exist_ok=True) 38 | api_url = f"https://insta.bdbots.xyz/dl?url={url}" 39 | 40 | try: 41 | async with aiohttp.ClientSession( 42 | connector=aiohttp.TCPConnector(limit=100), 43 | timeout=aiohttp.ClientTimeout(total=30) 44 | ) as session: 45 | async with session.get(api_url) as response: 46 | LOGGER.info(f"API request to {api_url} returned status {response.status}") 47 | if response.status != 200: 48 | LOGGER.error(f"API request failed: HTTP status {response.status}") 49 | return None 50 | data = await response.json() 51 | LOGGER.info(f"API response: {data}") 52 | if data.get("status") != "success": 53 | LOGGER.error("API response indicates failure") 54 | return None 55 | 56 | api_content_type = data["data"]["type"] 57 | await downloading_message.edit_text( 58 | "**Found ☑️ Downloading...**" if content_type == "video" else "**📤 Uploading...**", 59 | parse_mode=ParseMode.MARKDOWN 60 | ) 61 | media_files = [] 62 | # Download all media files concurrently 63 | tasks = [ 64 | self._download_file( 65 | session, 66 | media["url"], 67 | self.temp_dir / await self.sanitize_filename( 68 | data['data']['username'], 69 | data['data']['metadata']['shortcode'], 70 | index, 71 | media['type'] 72 | ) 73 | ) 74 | for index, media in enumerate(data["data"]["media"]) 75 | ] 76 | downloaded_files = await asyncio.gather(*tasks, return_exceptions=True) 77 | 78 | for index, result in enumerate(downloaded_files): 79 | if isinstance(result, Exception): 80 | LOGGER.error(f"Failed to download media {index}: {result}") 81 | continue 82 | media_files.append({ 83 | "filename": str(result), 84 | "type": data["data"]["media"][index]["type"] 85 | }) 86 | 87 | if not media_files: 88 | LOGGER.error("No media files downloaded successfully") 89 | return None 90 | 91 | return { 92 | "title": data["data"].get("caption", "Instagram Content"), 93 | "media_files": media_files, 94 | "webpage_url": url, 95 | "username": data["data"]["username"], 96 | "type": api_content_type 97 | } 98 | except aiohttp.ClientError as e: 99 | LOGGER.error(f"Instagram download error: {e}") 100 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}in", e, downloading_message) 101 | return None 102 | except asyncio.TimeoutError: 103 | LOGGER.error("Request to Instagram API timed out") 104 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}in", asyncio.TimeoutError("Request to Instagram API timed out"), downloading_message) 105 | return None 106 | except Exception as e: 107 | LOGGER.error(f"Instagram download error: {e}") 108 | await notify_admin(downloading_message._client, f"{COMMAND_PREFIX}in", e, downloading_message) 109 | return None 110 | 111 | async def _download_file(self, session: aiohttp.ClientSession, url: str, dest: Path) -> Path: 112 | try: 113 | async with session.get(url) as response: 114 | if response.status == 200: 115 | LOGGER.info(f"Downloading file from {url} to {dest}") 116 | async with aiofiles.open(dest, mode='wb') as f: 117 | async for chunk in response.content.iter_chunked(1024 * 1024): # 1MB chunks 118 | await f.write(chunk) 119 | LOGGER.info(f"File downloaded successfully to {dest}") 120 | return dest 121 | raise Exception(f"Failed to download {url}: Status {response.status}") 122 | except aiohttp.ClientError as e: 123 | LOGGER.error(f"Error downloading file from {url}: {e}") 124 | raise 125 | 126 | def setup_insta_handlers(app: Client): 127 | ig_downloader = InstagramDownloader(Config.TEMP_DIR) 128 | 129 | command_prefix_regex = f"[{''.join(map(re.escape, COMMAND_PREFIX))}]" 130 | 131 | @app.on_message(filters.regex(rf"^{command_prefix_regex}in(\s+https?://\S+)?$") & (filters.private | filters.group)) 132 | async def ig_handler(client: Client, message: Message): 133 | # Check if user is banned 134 | user_id = message.from_user.id if message.from_user else None 135 | if user_id and banned_users.find_one({"user_id": user_id}): 136 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**", parse_mode=ParseMode.MARKDOWN) 137 | return 138 | 139 | url = None 140 | # Check if URL from reply 141 | if message.reply_to_message and message.reply_to_message.text: 142 | match = re.search(r"https?://(www\.)?instagram\.com/(reel|p)/\S+", message.reply_to_message.text) 143 | if match: 144 | url = match.group(0) 145 | # Check if URL from command 146 | if not url: 147 | command_parts = message.text.split(maxsplit=1) 148 | if len(command_parts) > 1: 149 | match = re.search(r"https?://(www\.)?instagram\.com/(reel|p)/\S+", command_parts[1]) 150 | if match: 151 | url = match.group(0) 152 | 153 | if not url: 154 | await client.send_message( 155 | chat_id=message.chat.id, 156 | text="**Please provide a valid Instagram Reels/Post URL or reply to a message with one ❌**", 157 | parse_mode=ParseMode.MARKDOWN 158 | ) 159 | LOGGER.warning(f"No Instagram URL provided, user: {user_id or 'unknown'}, chat: {message.chat.id}") 160 | return 161 | 162 | LOGGER.info(f"Instagram URL received: {url}, user: {user_id or 'unknown'}, chat: {message.chat.id}") 163 | content_type = "video" if "/reel/" in url else "post" 164 | downloading_message = await client.send_message( 165 | chat_id=message.chat.id, 166 | text="**Searching The Video**" if content_type == "video" else "**🔍 Fetching media from Instagram...**", 167 | parse_mode=ParseMode.MARKDOWN 168 | ) 169 | 170 | try: 171 | content_info = await ig_downloader.download_content(url, downloading_message, content_type) 172 | if not content_info: 173 | await downloading_message.edit_text( 174 | "**Unable To Extract The URL 😕**", parse_mode=ParseMode.MARKDOWN 175 | ) 176 | LOGGER.error(f"Failed to download content for URL: {url}") 177 | return 178 | 179 | title = content_info["title"] 180 | media_files = content_info["media_files"] 181 | webpage_url = content_info["webpage_url"] 182 | content_type = content_info["type"] 183 | username = content_info["username"] 184 | 185 | if message.from_user: 186 | user_full_name = f"{message.from_user.first_name} {message.from_user.last_name or ''}".strip() 187 | user_info = f"[{user_full_name}](tg://user?id={user_id})" 188 | else: 189 | group_name = message.chat.title or "this squad" 190 | group_url = f"https://t.me/{message.chat.username}" if message.chat.username else "this squad" 191 | user_info = f"[{group_name}]({group_url})" 192 | 193 | caption = ( 194 | f"🔥 **Insta DL Success!** ✅\n" 195 | f"🎬 **Title**: `{title}`\n" 196 | f"📸 **Uploader**: `@{username}`\n" 197 | f"🌐 **Link**: [View on Instagram]({webpage_url})\n" 198 | f"👉 **Downloaded By**: {user_info}\n" 199 | f"#InstaVibes #ReelIt" 200 | ) if content_type == "video" else ( 201 | f"📸 **Insta Post Downloaded!** ✅\n" 202 | f"🎨 **Caption**: `{title}`\n" 203 | f"👤 **Uploader**: `@{username}`\n" 204 | f"🌐 **Link**: [View on Instagram]({webpage_url})\n" 205 | f"👉 **Downloaded By**: {user_info}\n" 206 | f"#InstaMoments #PostVibes" 207 | ) 208 | 209 | inline_keyboard = InlineKeyboardMarkup( 210 | [[InlineKeyboardButton("🔍 View on Insta", url=webpage_url)]] 211 | ) if content_type == "video" else None 212 | 213 | if content_type == "carousel" and len(media_files) > 1: 214 | # Split media files into chunks of MAX_MEDIA_PER_GROUP 215 | for i in range(0, len(media_files), Config.MAX_MEDIA_PER_GROUP): 216 | media_group = [] 217 | for index, media in enumerate(media_files[i:i + Config.MAX_MEDIA_PER_GROUP]): 218 | media_type = InputMediaPhoto if media["type"] == "image" else InputMediaVideo 219 | media_group.append( 220 | media_type( 221 | media=media["filename"], 222 | caption=caption if index == 0 and i == 0 else "", 223 | parse_mode=ParseMode.MARKDOWN 224 | ) 225 | ) 226 | await client.send_media_group( 227 | chat_id=message.chat.id, 228 | media=media_group 229 | ) 230 | else: 231 | media = media_files[0] 232 | async with aiofiles.open(media["filename"], 'rb'): 233 | if media["type"] == "video": 234 | start_time = time.time() 235 | last_update_time = [start_time] 236 | await client.send_video( 237 | chat_id=message.chat.id, 238 | video=media["filename"], 239 | supports_streaming=True, 240 | caption=caption, 241 | parse_mode=ParseMode.MARKDOWN, 242 | reply_markup=inline_keyboard, 243 | progress=progress_bar, 244 | progress_args=(downloading_message, start_time, last_update_time) 245 | ) 246 | else: 247 | await client.send_photo( 248 | chat_id=message.chat.id, 249 | photo=media["filename"], 250 | caption=caption, 251 | parse_mode=ParseMode.MARKDOWN 252 | ) 253 | 254 | await downloading_message.delete() 255 | # Clean up files asynchronously 256 | for media in media_files: 257 | if os.path.exists(media["filename"]): 258 | os.remove(media["filename"]) 259 | LOGGER.info(f"Deleted media file: {media['filename']}") 260 | 261 | except Exception as e: 262 | LOGGER.error(f"Error processing Instagram content: {e}") 263 | await notify_admin(client, f"{COMMAND_PREFIX}in", e, downloading_message) 264 | await downloading_message.edit_text( 265 | "**Instagram Downloader API Down**", parse_mode=ParseMode.MARKDOWN 266 | ) -------------------------------------------------------------------------------- /modules/dlxutils/spfy.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import os 5 | import time 6 | import requests 7 | import aiohttp 8 | import re 9 | import asyncio 10 | import aiofiles 11 | from pathlib import Path 12 | from concurrent.futures import ThreadPoolExecutor 13 | from pyrogram import Client, filters 14 | from pyrogram.enums import ParseMode 15 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton 16 | from typing import Optional 17 | from config import COMMAND_PREFIX 18 | from utils import LOGGER, progress_bar, notify_admin # Import LOGGER, progress_bar, and notify_admin from utils 19 | from core import banned_users # Check if user is banned 20 | import urllib.parse 21 | 22 | # Use the imported LOGGER 23 | logger = LOGGER 24 | 25 | # Configuration 26 | class Config: 27 | TEMP_DIR = Path("temp") 28 | 29 | Config.TEMP_DIR.mkdir(exist_ok=True) 30 | 31 | # ThreadPoolExecutor for blocking I/O operations 32 | executor = ThreadPoolExecutor(max_workers=10) 33 | 34 | async def sanitize_filename(title: str) -> str: 35 | """Sanitize file name by removing invalid characters.""" 36 | title = re.sub(r'[<>:"/\\|?*]', '', title[:50]).strip() 37 | return f"{title.replace(' ', '_')}_{int(time.time())}" 38 | 39 | async def download_image(url: str, output_path: str) -> Optional[str]: 40 | """Download image from a URL.""" 41 | logger.info(f"Starting download of image from {url}") 42 | try: 43 | async with aiohttp.ClientSession() as session: 44 | async with session.get(url) as response: 45 | if response.status == 200: 46 | async with aiofiles.open(output_path, 'wb') as file: 47 | await file.write(await response.read()) 48 | logger.info(f"Image downloaded successfully to {output_path}") 49 | return output_path 50 | else: 51 | logger.error(f"Failed to download image: HTTP status {response.status}") 52 | # Notify admins 53 | await notify_admin(None, f"{COMMAND_PREFIX}sp", Exception(f"Failed to download image: HTTP status {response.status}"), None) 54 | except Exception as e: 55 | logger.error(f"Failed to download image: {e}") 56 | # Notify admins 57 | await notify_admin(None, f"{COMMAND_PREFIX}sp", e, None) 58 | return None 59 | 60 | async def handle_spotify_request(client: Client, message: Message, input_text: Optional[str]): 61 | # Check if the message is a reply to another message 62 | if not input_text and message.reply_to_message and message.reply_to_message.text: 63 | input_text = message.reply_to_message.text.strip() 64 | 65 | if not input_text: 66 | await client.send_message( 67 | chat_id=message.chat.id, 68 | text="**Please provide a track Spotify URL**", 69 | parse_mode=ParseMode.MARKDOWN 70 | ) 71 | logger.warning(f"No input provided, user: {message.from_user.id if message.from_user else 'unknown'}, chat: {message.chat.id}") 72 | return 73 | 74 | # Check if input_text is a URL (starts with http) 75 | is_url = input_text.lower().startswith('http') 76 | 77 | status_message = await client.send_message( 78 | chat_id=message.chat.id, 79 | text="**Searching The Music**", 80 | parse_mode=ParseMode.MARKDOWN 81 | ) 82 | 83 | try: 84 | async with aiohttp.ClientSession() as session: 85 | if is_url: 86 | # Handle Spotify URL 87 | logger.info(f"Processing Spotify URL: {input_text}") 88 | api_url = f"https://abirthetech.serv00.net/sp.php?url={urllib.parse.quote(input_text)}" 89 | async with session.get(api_url) as response: 90 | if response.status == 200: 91 | data = await response.json() 92 | logger.info(f"Track API response: {data}") 93 | if data["status"]: 94 | await status_message.edit_text("**Found ☑️ Downloading...**", parse_mode=ParseMode.MARKDOWN) 95 | else: 96 | await status_message.edit_text("**Please Provide A Valid Spotify URL ❌**", parse_mode=ParseMode.MARKDOWN) 97 | logger.error(f"Invalid Spotify URL: {input_text}") 98 | return 99 | else: 100 | await status_message.edit_text("**❌ Song Not Available On Spotify**", parse_mode=ParseMode.MARKDOWN) 101 | logger.error(f"API request failed: HTTP status {response.status}") 102 | # Notify admins 103 | await notify_admin(client, f"{COMMAND_PREFIX}sp", Exception(f"API request failed: HTTP status {response.status}"), message) 104 | return 105 | else: 106 | # Handle search query 107 | logger.info(f"Processing Spotify search query: {input_text}") 108 | encoded_query = urllib.parse.quote(input_text) 109 | api_url = f"https://abirthetech.serv00.net/sps.php?q={encoded_query}" 110 | async with session.get(api_url) as response: 111 | if response.status == 200: 112 | data = await response.json() 113 | logger.info(f"Search API response: {data}") 114 | if data["type"] == "search" and data["data"]: 115 | await status_message.edit_text("**Found ☑️ Downloading...**", parse_mode=ParseMode.MARKDOWN) 116 | # Use the first result 117 | track = data["data"][0] 118 | # Fetch track details using the Spotify URL 119 | track_url = track["external_urls"]["spotify"] 120 | logger.info(f"Selected track: {track['name']} (URL: {track_url})") 121 | track_api_url = f"https://abirthetech.serv00.net/sp.php?url={urllib.parse.quote(track_url)}" 122 | async with session.get(track_api_url) as track_response: 123 | if track_response.status == 200: 124 | data = await track_response.json() 125 | logger.info(f"Track API response: {data}") 126 | if not data["status"]: 127 | await status_message.edit_text("**Song Metadata Unavailable**", parse_mode=ParseMode.MARKDOWN) 128 | logger.error("Song metadata unavailable") 129 | # Notify admins 130 | await notify_admin(client, f"{COMMAND_PREFIX}sp", Exception("Song metadata unavailable"), message) 131 | return 132 | else: 133 | await status_message.edit_text("**❌ Song Unavailable Bro Try Later**", parse_mode=ParseMode.MARKDOWN) 134 | logger.error(f"Track API request failed: HTTP status {track_response.status}") 135 | # Notify admins 136 | await notify_admin(client, f"{COMMAND_PREFIX}sp", Exception(f"Track API request failed: HTTP status {track_response.status}"), message) 137 | return 138 | else: 139 | await status_message.edit_text("**Sorry No Songs Matched To Your Search!**", parse_mode=ParseMode.MARKDOWN) 140 | logger.error(f"No songs matched search query: {input_text}") 141 | return 142 | else: 143 | await status_message.edit_text("**❌ Sorry Bro Spotify Search API Dead**", parse_mode=ParseMode.MARKDOWN) 144 | logger.error(f"Search API request failed: HTTP status {response.status}") 145 | # Notify admins 146 | await notify_admin(client, f"{COMMAND_PREFIX}sp", Exception(f"Search API request failed: HTTP status {response.status}"), message) 147 | return 148 | 149 | # Extract track details from API response 150 | title = data["title"] 151 | artists = data["artist"] 152 | duration = data["duration"] 153 | album = data["album"] 154 | release_date = data["releaseDate"] 155 | spotify_url = data["spotify_url"] 156 | download_url = data["download_link"] 157 | cover_url = data.get("image") or data.get("cover") 158 | 159 | # Download cover image 160 | cover_path = None 161 | if cover_url: 162 | Config.TEMP_DIR.mkdir(exist_ok=True) 163 | cover_path = Config.TEMP_DIR / f"{await sanitize_filename(title)}.jpg" 164 | downloaded_path = await download_image(cover_url, str(cover_path)) 165 | if downloaded_path: 166 | logger.info(f"Cover image downloaded to {downloaded_path}") 167 | else: 168 | logger.warning("Failed to download cover image") 169 | cover_path = None 170 | 171 | # Download audio 172 | safe_title = await sanitize_filename(title) 173 | output_filename = Config.TEMP_DIR / f"{safe_title}.mp3" 174 | logger.info(f"Starting download of audio file from {download_url}") 175 | async with session.get(download_url) as response: 176 | if response.status == 200: 177 | async with aiofiles.open(output_filename, 'wb') as file: 178 | await file.write(await response.read()) 179 | logger.info(f"Audio file downloaded successfully to {output_filename}") 180 | else: 181 | await status_message.edit_text("**❌ Sorry Bro Spotify DL API Dead**", parse_mode=ParseMode.MARKDOWN) 182 | logger.error(f"Audio download failed: HTTP status {response.status}") 183 | # Notify admins 184 | await notify_admin(client, f"{COMMAND_PREFIX}sp", Exception(f"Audio download failed: HTTP status {response.status}"), message) 185 | return 186 | 187 | # Prepare user info for caption 188 | if message.from_user: 189 | user_full_name = f"{message.from_user.first_name} {message.from_user.last_name or ''}".strip() 190 | user_info = f"[{user_full_name}](tg://user?id={message.from_user.id})" 191 | else: 192 | group_name = message.chat.title or "this group" 193 | group_url = f"https://t.me/{message.chat.username}" if message.chat.username else "this group" 194 | user_info = f"[{group_name}]({group_url})" 195 | 196 | # Format caption 197 | audio_caption = ( 198 | f"🌟 **Title**: `{title}`\n" 199 | f"💥 **Artist**: `{artists}`\n" 200 | f"✨ **Duration**: `{duration}`\n" 201 | f"👀 **Album**: `{album}`\n" 202 | f"🎵 **Release Date**: `{release_date}`\n" 203 | f"━━━━━━━━━━━━━━━━━━━\n" 204 | f"**Downloaded By**: {user_info}" 205 | ) 206 | 207 | # Create inline button for Spotify URL 208 | reply_markup = InlineKeyboardMarkup([ 209 | [InlineKeyboardButton("🎸 Listen On Spotify", url=spotify_url)] 210 | ]) 211 | 212 | last_update_time = [0] 213 | start_time = time.time() 214 | 215 | logger.info("Starting upload of audio file to Telegram") 216 | await client.send_audio( 217 | chat_id=message.chat.id, 218 | audio=str(output_filename), 219 | caption=audio_caption, 220 | title=title, 221 | performer=artists, 222 | parse_mode=ParseMode.MARKDOWN, 223 | thumb=str(cover_path) if cover_path else None, 224 | reply_markup=reply_markup, 225 | progress=progress_bar, 226 | progress_args=(status_message, start_time, last_update_time) 227 | ) 228 | logger.info("Upload of audio successfully completed") 229 | 230 | if os.path.exists(output_filename): 231 | os.remove(output_filename) 232 | logger.info(f"Deleted audio file: {output_filename}") 233 | if cover_path and os.path.exists(cover_path): 234 | os.remove(cover_path) 235 | logger.info(f"Deleted cover image: {cover_path}") 236 | 237 | await status_message.delete() 238 | logger.info("Status message deleted") 239 | except Exception as e: 240 | await status_message.edit_text("**❌ Sorry Bro Spotify DL API Dead**", parse_mode=ParseMode.MARKDOWN) 241 | logger.error(f"Error processing Spotify request: {str(e)}") 242 | # Notify admins 243 | await notify_admin(client, status_message, f"{COMMAND_PREFIX}sp", Exception(str(e))) 244 | 245 | def setup_spotify_handler(app: Client): 246 | """Set up the Spotify command handler.""" 247 | # Create a regex pattern from the COMMAND_PREFIX list 248 | command_prefix_regex = rf"[{''.join(map(re.escape, COMMAND_PREFIX))}]" 249 | 250 | @app.on_message(filters.regex(rf"^{command_prefix_regex}sp(\s+.*)?$") & (filters.private | filters.group)) 251 | async def spotify_command(client: Client, message: Message): 252 | # Check if user is banned 253 | user_id = message.from_user.id if message.from_user else None 254 | if user_id and banned_users.find_one({"user_id": user_id}): 255 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**") 256 | return 257 | 258 | # Check if the message contains a Spotify URL or query 259 | command_parts = message.text.split(maxsplit=1) 260 | input_text = command_parts[1].strip() if len(command_parts) > 1 else None 261 | logger.info(f"Spotify command received: input_text='{input_text or 'None'}', user: {user_id or 'unknown'}, chat: {message.chat.id}") 262 | await handle_spotify_request(client, message, input_text) -------------------------------------------------------------------------------- /sudoers/admin/admin.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | import asyncio 5 | from pyrogram import Client, filters 6 | from pyrogram.handlers import MessageHandler 7 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message 8 | from pyrogram.enums import ParseMode 9 | from datetime import datetime, timedelta 10 | from config import OWNER_ID, UPDATE_CHANNEL_URL, COMMAND_PREFIX, DEVELOPER_USER_ID 11 | from core import auth_admins, user_activity_collection 12 | from utils import LOGGER 13 | 14 | # Function to update user activity in the MongoDB database 15 | def update_user_activity(user_id, is_group=False): 16 | try: 17 | now = datetime.utcnow() 18 | user = user_activity_collection.find_one({"user_id": user_id}) 19 | if not user: 20 | user_activity_collection.insert_one({ 21 | "user_id": user_id, 22 | "is_group": is_group, 23 | "last_activity": now, 24 | "daily": 0, 25 | "weekly": 0, 26 | "monthly": 0, 27 | "yearly": 0 28 | }) 29 | LOGGER.info(f"Inserted new user activity for user_id {user_id}, is_group={is_group}") 30 | else: 31 | user_activity_collection.update_one( 32 | {"user_id": user_id}, 33 | {"$set": {"last_activity": now}}, 34 | upsert=True 35 | ) 36 | user_activity_collection.update_one( 37 | {"user_id": user_id}, 38 | {"$inc": {"daily": 1, "weekly": 1, "monthly": 1, "yearly": 1}}, 39 | ) 40 | LOGGER.debug(f"Updated activity for user_id {user_id}, is_group={is_group}") 41 | except Exception as e: 42 | LOGGER.error(f"Error updating user activity for user_id {user_id}: {e}") 43 | 44 | def is_admin(user_id): 45 | auth_admins_data = auth_admins.find({}, {"user_id": 1, "_id": 0}) 46 | AUTH_ADMIN_IDS = [admin["user_id"] for admin in auth_admins_data] 47 | return user_id == OWNER_ID or user_id in AUTH_ADMIN_IDS 48 | 49 | async def broadcast_handler(client: Client, message: Message): 50 | user_id = message.from_user.id 51 | if not is_admin(user_id): 52 | LOGGER.info(f"Unauthorized broadcast attempt by user_id {user_id}") 53 | await client.send_message( 54 | chat_id=message.chat.id, 55 | text="**✘Kids Not Allowed To Do This↯**", 56 | parse_mode=ParseMode.MARKDOWN 57 | ) 58 | return 59 | 60 | is_broadcast = message.command[0].lower() in ["broadcast", "b"] 61 | LOGGER.info(f"{'Broadcast' if is_broadcast else 'Send'} command initiated by user_id {user_id}") 62 | 63 | if message.reply_to_message: 64 | # Admin replies to a message with the command 65 | await process_broadcast(client, message.reply_to_message, is_broadcast, message.chat.id) 66 | elif is_broadcast and len(message.command) > 1: 67 | # Admin uses command with text to broadcast directly 68 | broadcast_text = " ".join(message.command[1:]) 69 | await process_broadcast(client, broadcast_text, is_broadcast, message.chat.id) 70 | else: 71 | # Admin sends just the command; bot waits for a message 72 | action_type = "broadcast" if is_broadcast else "send" 73 | await client.send_message( 74 | chat_id=message.chat.id, 75 | text=f"**Please send the message you want to {action_type}.**", 76 | parse_mode=ParseMode.MARKDOWN 77 | ) 78 | 79 | # Define the callback to handle the next message 80 | async def broadcast_message_callback(client: Client, broadcast_msg: Message): 81 | if broadcast_msg.from_user.id == message.from_user.id and broadcast_msg.chat.id == message.chat.id: 82 | await process_broadcast(client, broadcast_msg, is_broadcast, message.chat.id) 83 | client.remove_handler(broadcast_message_handler, group=1) 84 | 85 | # Add a temporary handler for the admin's next message 86 | broadcast_message_handler = MessageHandler( 87 | broadcast_message_callback, 88 | filters.user(message.from_user.id) & filters.chat(message.chat.id) 89 | ) 90 | client.add_handler(broadcast_message_handler, group=1) 91 | 92 | async def process_broadcast(client: Client, content, is_broadcast=True, chat_id=None): 93 | try: 94 | if isinstance(content, str): 95 | broadcast_text = content 96 | broadcast_msg = None 97 | elif isinstance(content, Message): 98 | broadcast_msg = content 99 | broadcast_text = None 100 | else: 101 | raise ValueError("Invalid content type") 102 | 103 | LOGGER.info(f"Processing {'broadcast' if is_broadcast else 'forward'} to users and groups") 104 | processing_message = await client.send_message( 105 | chat_id=chat_id, 106 | text=f'**💫 {"Broadcasting" if is_broadcast else "Sending"} Message In Progress 💫**', 107 | parse_mode=ParseMode.MARKDOWN 108 | ) 109 | 110 | user_ids = [user["user_id"] for user in user_activity_collection.find({"is_group": False})] 111 | group_ids = [group["user_id"] for group in user_activity_collection.find({"is_group": True})] 112 | 113 | successful_users = 0 114 | failed_users = 0 115 | successful_groups = 0 116 | failed_groups = 0 117 | broadcast_start_time = datetime.now() 118 | 119 | keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("💥 Bot Updates 💥", url=UPDATE_CHANNEL_URL)]]) 120 | 121 | for target_chat_id in user_ids + group_ids: 122 | try: 123 | if broadcast_text: 124 | await client.send_message( 125 | chat_id=target_chat_id, 126 | text=broadcast_text, 127 | reply_markup=keyboard 128 | ) 129 | elif broadcast_msg: 130 | if is_broadcast: 131 | # Broadcast (copy) method 132 | if broadcast_msg.text: 133 | await client.send_message( 134 | chat_id=target_chat_id, 135 | text=broadcast_msg.text, 136 | reply_markup=keyboard 137 | ) 138 | elif broadcast_msg.photo: 139 | await client.send_photo( 140 | chat_id=target_chat_id, 141 | photo=broadcast_msg.photo.file_id, 142 | caption=broadcast_msg.caption or "", 143 | reply_markup=keyboard 144 | ) 145 | elif broadcast_msg.video: 146 | await client.send_video( 147 | chat_id=target_chat_id, 148 | video=broadcast_msg.video.file_id, 149 | caption=broadcast_msg.caption or "", 150 | reply_markup=keyboard 151 | ) 152 | elif broadcast_msg.audio: 153 | await client.send_audio( 154 | chat_id=target_chat_id, 155 | audio=broadcast_msg.audio.file_id, 156 | caption=broadcast_msg.caption or "", 157 | reply_markup=keyboard 158 | ) 159 | elif broadcast_msg.document: 160 | await client.send_document( 161 | chat_id=target_chat_id, 162 | document=broadcast_msg.document.file_id, 163 | caption=broadcast_msg.caption or "", 164 | reply_markup=keyboard 165 | ) 166 | else: 167 | await client.copy_message( 168 | chat_id=target_chat_id, 169 | from_chat_id=broadcast_msg.chat.id, 170 | message_id=broadcast_msg.id 171 | ) 172 | else: 173 | # Forward method 174 | await client.forward_messages( 175 | chat_id=target_chat_id, 176 | from_chat_id=broadcast_msg.chat.id, 177 | message_ids=broadcast_msg.id 178 | ) 179 | if target_chat_id in user_ids: 180 | successful_users += 1 181 | else: 182 | successful_groups += 1 183 | except Exception as e: 184 | LOGGER.error(f"Failed to {'broadcast' if is_broadcast else 'forward'} to chat_id {target_chat_id}: {e}") 185 | if target_chat_id in user_ids: 186 | failed_users += 1 187 | else: 188 | failed_groups += 1 189 | 190 | broadcast_end_time = datetime.now() 191 | time_diff = broadcast_end_time - broadcast_start_time 192 | hours, remainder = divmod(time_diff.seconds, 3600) 193 | minutes, seconds = divmod(remainder, 60) 194 | time_taken = f"{hours}h {minutes}m {seconds}s" if hours > 0 else f"{minutes}m {seconds}s" if minutes > 0 else f"{seconds}s" 195 | 196 | await processing_message.delete() 197 | 198 | action_success = "Broadcast" if is_broadcast else "Forward" 199 | LOGGER.info(f"{action_success} completed: {successful_users} users, {successful_groups} groups, {failed_users} failed users, {failed_groups} failed groups") 200 | 201 | await client.send_message( 202 | chat_id=chat_id, 203 | text=f"**💥 Hey Bro! {action_success} Successful ! 💥**\n" 204 | "**✘━━━━━━━━━━━✘**\n" 205 | f"**👀 To Users:** `{successful_users}` ✨\n" 206 | f"**✘ Blocked Users** `{failed_users}` ❄️\n" 207 | "**✘━━━━━━━━━━━✘**\n" 208 | f"**🌐 To Groups** `{successful_groups}` 🌟\n" 209 | f"**✘ Blocked Groups** `{failed_groups}` 💫\n" 210 | "**✘━━━━━━━━━━━✘**\n" 211 | f"**↯ Time Taken** `{time_taken}` 🇧🇩", 212 | parse_mode=ParseMode.MARKDOWN, 213 | reply_markup=InlineKeyboardMarkup( 214 | [[InlineKeyboardButton("💥 Bot Updates 💥", url=UPDATE_CHANNEL_URL)]] 215 | ) 216 | ) 217 | except Exception as e: 218 | LOGGER.error(f"Error processing {'broadcast' if is_broadcast else 'forward'}: {e}") 219 | await client.send_message( 220 | chat_id=chat_id, 221 | text="**✘ Error Processing Broadcast/Forward!**", 222 | parse_mode=ParseMode.MARKDOWN 223 | ) 224 | 225 | async def stats_handler(client: Client, message: Message): 226 | user_id = message.from_user.id 227 | if not is_admin(user_id): 228 | LOGGER.info(f"Unauthorized stats attempt by user_id {user_id}") 229 | await client.send_message( 230 | chat_id=message.chat.id, 231 | text="**✘Kids Not Allowed To Do This↯**", 232 | parse_mode=ParseMode.MARKDOWN 233 | ) 234 | return 235 | 236 | LOGGER.info(f"Stats command initiated by user_id {user_id}") 237 | try: 238 | now = datetime.utcnow() 239 | daily_users = user_activity_collection.count_documents({"is_group": False, "last_activity": {"$gt": now - timedelta(days=1)}}) 240 | weekly_users = user_activity_collection.count_documents({"is_group": False, "last_activity": {"$gt": now - timedelta(weeks=1)}}) 241 | monthly_users = user_activity_collection.count_documents({"is_group": False, "last_activity": {"$gt": now - timedelta(days=30)}}) 242 | yearly_users = user_activity_collection.count_documents({"is_group": False, "last_activity": {"$gt": now - timedelta(days=365)}}) 243 | 244 | total_users = user_activity_collection.count_documents({"is_group": False}) 245 | total_groups = user_activity_collection.count_documents({"is_group": True}) 246 | 247 | stats_text = ( 248 | "**💥 Bot's Full Database Info 💥**\n" 249 | "**✘━━━━━━━━━━━✘**\n" 250 | "**✨ Registered Users Activity: ✨**\n" 251 | f"- 💫 Daily Active: {daily_users} 🔥\n" 252 | f"- 🌟 Weekly Active: {weekly_users} ⚡\n" 253 | f"- ❄️ Monthly Active: {monthly_users} 🌈\n" 254 | f"- 👀 Annual Active: {yearly_users} 🎯\n" 255 | "**✘━━━━━━━━━━━✘**\n" 256 | "**✘ Total Metrics: ✘**\n" 257 | f"- 👥 Total Users: {total_users} 💫\n" 258 | f"- 🌐 Total Groups: {total_groups} 🌟\n" 259 | f"- ↯ Database Size: {total_users + total_groups} ✨\n" 260 | ) 261 | 262 | keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("💥 Bot Updates 💥", url=UPDATE_CHANNEL_URL)]]) 263 | await client.send_message( 264 | chat_id=message.chat.id, 265 | text=stats_text, 266 | parse_mode=ParseMode.MARKDOWN, 267 | reply_markup=keyboard, 268 | disable_web_page_preview=True 269 | ) 270 | LOGGER.info("Stats command completed successfully") 271 | except Exception as e: 272 | LOGGER.error(f"Error processing stats: {e}") 273 | await client.send_message( 274 | chat_id=message.chat.id, 275 | text="**✘ Error Processing Stats!**", 276 | parse_mode=ParseMode.MARKDOWN 277 | ) 278 | 279 | async def group_added_handler(client: Client, message: Message): 280 | try: 281 | for new_member in message.new_chat_members: 282 | if new_member.is_self: 283 | chat_id = message.chat.id 284 | update_user_activity(chat_id, is_group=True) 285 | await client.send_message( 286 | chat_id=chat_id, 287 | text="**💥 Thank You For Adding Me In This Group! 💫**\n" 288 | "**✘ ━━━━━━━━━━━━━━━━━━ ✘**\n" 289 | "**✨ I'm here to assist you with various tasks and make your group experience better.\n" 290 | "↯ Feel free to explore my features and let me know if you need any help! 🌟**\n" 291 | "**✘ ━━━━━━━━━━━━━━━━━━ ✘**", 292 | parse_mode=ParseMode.MARKDOWN, 293 | reply_markup=InlineKeyboardMarkup([ 294 | [InlineKeyboardButton("➕ Add Me 💥", url="https://t.me/ItsSmartToolBot?startgroup=new&admin=post_messages+delete_messages+edit_messages+pin_messages+change_info+invite_users+promote_members"), 295 | InlineKeyboardButton("My Dev 💫", user_id=DEVELOPER_USER_ID)] 296 | ]) 297 | ) 298 | LOGGER.info(f"Bot added to group {chat_id}") 299 | except Exception as e: 300 | LOGGER.error(f"Error in group_added_handler for chat_id {message.chat.id}: {e}") 301 | 302 | def setup_admin_handler(app: Client): 303 | """ 304 | Set up command handlers for the Pyrogram bot. 305 | This includes specific commands like /broadcast and /stats, as well as general activity tracking. 306 | """ 307 | app.add_handler( 308 | MessageHandler( 309 | broadcast_handler, 310 | (filters.command(["broadcast", "b"]) | filters.command(["broadcast", "b"], prefixes=COMMAND_PREFIX) | 311 | filters.command(["send", "s"]) | filters.command(["send", "s"], prefixes=COMMAND_PREFIX)) & 312 | (filters.private | filters.group) 313 | ), 314 | group=1, 315 | ) 316 | 317 | app.add_handler( 318 | MessageHandler( 319 | stats_handler, 320 | (filters.command(["stats", "report", "status"]) | 321 | filters.command(["stats", "report", "status"], prefixes=COMMAND_PREFIX)) & 322 | (filters.private | filters.group) 323 | ), 324 | group=1, 325 | ) 326 | 327 | app.add_handler( 328 | MessageHandler( 329 | lambda client, message: update_user_activity(message.from_user.id) if message.from_user else None, 330 | filters.all 331 | ), 332 | group=2, 333 | ) 334 | 335 | app.add_handler( 336 | MessageHandler( 337 | group_added_handler, 338 | filters.group & filters.new_chat_members 339 | ), 340 | group=1 341 | ) 342 | -------------------------------------------------------------------------------- /modules/infoxutils/info.py: -------------------------------------------------------------------------------- 1 | # Copyright @ISmartDevs 2 | # Channel t.me/TheSmartDev 3 | 4 | from datetime import datetime, timedelta 5 | from dateutil.relativedelta import relativedelta 6 | from pyrogram import filters, Client 7 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup 8 | from pyrogram.enums import ParseMode, ChatType, UserStatus 9 | from pyrogram.errors import PeerIdInvalid, UsernameNotOccupied, ChannelInvalid 10 | from config import COMMAND_PREFIX 11 | from utils import LOGGER, get_dc_locations # Use LOGGER from utils 12 | from core import banned_users # Check if user is banned 13 | 14 | # Use the imported LOGGER 15 | logger = LOGGER 16 | 17 | # Function to calculate account age accurately 18 | def calculate_account_age(creation_date): 19 | today = datetime.now() 20 | delta = relativedelta(today, creation_date) 21 | years = delta.years 22 | months = delta.months 23 | days = delta.days 24 | return f"{years} years, {months} months, {days} days" 25 | 26 | # Function to estimate account creation date based on user ID 27 | def estimate_account_creation_date(user_id): 28 | # Known reference points for user IDs and their creation dates 29 | reference_points = [ 30 | (100000000, datetime(2013, 8, 1)), # Telegram's launch date 31 | (1273841502, datetime(2020, 8, 13)), # Example reference point 32 | (1500000000, datetime(2021, 5, 1)), # Another reference point 33 | (2000000000, datetime(2022, 12, 1)), # Another reference point 34 | ] 35 | 36 | # Find the closest reference point 37 | closest_point = min(reference_points, key=lambda x: abs(x[0] - user_id)) 38 | closest_user_id, closest_date = closest_point 39 | 40 | # Calculate the difference in user IDs 41 | id_difference = user_id - closest_user_id 42 | 43 | # Estimate the creation date based on the difference 44 | # Assuming 20,000,000 user IDs are created per day (adjusted for estimation) 45 | days_difference = id_difference / 20000000 46 | creation_date = closest_date + timedelta(days=days_difference) 47 | 48 | return creation_date 49 | 50 | def setup_info_handler(app): 51 | @app.on_message(filters.command(["info", "id"], prefixes=COMMAND_PREFIX) & (filters.private | filters.group)) 52 | async def handle_info_command(client: Client, message: Message): 53 | # Check if user is banned 54 | user_id = message.from_user.id if message.from_user else None 55 | if user_id and banned_users.find_one({"user_id": user_id}): 56 | await client.send_message(message.chat.id, "**✘Sorry You're Banned From Using Me↯**") 57 | return 58 | 59 | logger.info("Received /info or /id command") 60 | try: 61 | # Get DC locations data from imported function 62 | DC_LOCATIONS = get_dc_locations() 63 | 64 | progress_message = await client.send_message(message.chat.id, "**✨ Smart Tools Fetching Info From Database 💥**") 65 | try: 66 | if not message.command or (len(message.command) == 1 and not message.reply_to_message): 67 | logger.info("Fetching current user info") 68 | user = message.from_user 69 | chat = message.chat 70 | premium_status = "Yes" if user.is_premium else "No" 71 | dc_location = DC_LOCATIONS.get(user.dc_id, "Unknown") 72 | account_created = estimate_account_creation_date(user.id) 73 | account_created_str = account_created.strftime("%B %d, %Y") 74 | account_age = calculate_account_age(account_created) 75 | 76 | # Added verification and status 77 | verified_status = "Yes" if getattr(user, 'is_verified', False) else "No" 78 | 79 | status = "⚪️ Unknown" 80 | if user.status: 81 | if user.status == UserStatus.ONLINE: 82 | status = "Online" 83 | elif user.status == UserStatus.OFFLINE: 84 | status = "Offline" 85 | elif user.status == UserStatus.RECENTLY: 86 | status = "Recently online" 87 | elif user.status == UserStatus.LAST_WEEK: 88 | status = "Last seen within week" 89 | elif user.status == UserStatus.LAST_MONTH: 90 | status = "Last seen within month" 91 | 92 | response = ( 93 | "✘《 **User Information** ↯ 》\n" 94 | f"↯ **Full Name:** {user.first_name} {user.last_name or ''}\n" 95 | f"↯ **User ID:** `{user.id}`\n" 96 | f"↯ **Username:** @{user.username if user.username else 'None'}\n" 97 | f"↯ **Chat Id:** `{chat.id}`\n" 98 | f"↯ **Data Center:** {user.dc_id} ({dc_location})\n" 99 | f"↯ **Premium User:** {premium_status}\n" 100 | f"↯ **Verified:** {verified_status}\n" 101 | f"↯ **Flags:** {'Scam' if getattr(user, 'is_scam', False) else 'Fake' if getattr(user, 'is_fake', False) else 'Clean'}\n" 102 | f"↯ **Status:** {status}\n" 103 | f"↯ **Account Created On:** {account_created_str}\n" 104 | f"↯ **Account Age:** {account_age}" 105 | ) 106 | buttons = [ 107 | [InlineKeyboardButton("✘ Android Link ↯", url=f"tg://openmessage?user_id={user.id}"), InlineKeyboardButton("✘ iOS Link ↯", url=f"tg://user?id={user.id}")], 108 | [InlineKeyboardButton("✘ Permanent Link ↯", url=f"tg://user?id={user.id}")], 109 | ] 110 | await client.send_message(chat_id=message.chat.id, text=response, parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(buttons)) 111 | logger.info("User info fetched successfully with buttons") 112 | elif message.reply_to_message: 113 | # Show info of the replied user or bot 114 | logger.info("Fetching info of the replied user or bot") 115 | user = message.reply_to_message.from_user 116 | chat = message.chat 117 | premium_status = "Yes" if user.is_premium else "No" 118 | dc_location = DC_LOCATIONS.get(user.dc_id, "Unknown") 119 | account_created = estimate_account_creation_date(user.id) 120 | account_created_str = account_created.strftime("%B %d, %Y") 121 | account_age = calculate_account_age(account_created) 122 | 123 | # Added verification and status 124 | verified_status = "Yes" if getattr(user, 'is_verified', False) else "No" 125 | 126 | status = "⚪️ Unknown" 127 | if user.status: 128 | if user.status == UserStatus.ONLINE: 129 | status = "Online" 130 | elif user.status == UserStatus.OFFLINE: 131 | status = "Offline" 132 | elif user.status == UserStatus.RECENTLY: 133 | status = "Recently online" 134 | elif user.status == UserStatus.LAST_WEEK: 135 | status = "Last seen within week" 136 | elif user.status == UserStatus.LAST_MONTH: 137 | status = "Last seen within month" 138 | 139 | response = ( 140 | "✘《 **User Information** ↯ 》\n" 141 | f"↯ **Full Name:** {user.first_name} {user.last_name or ''}\n" 142 | f"↯ **User ID:** `{user.id}`\n" 143 | f"↯ **Username:** @{user.username if user.username else 'None'}\n" 144 | f"↯ **Chat Id:** `{chat.id}`\n" 145 | f"↯ **Data Center:** {user.dc_id} ({dc_location})\n" 146 | f"↯ **Premium User:** {premium_status}\n" 147 | f"↯ **Verified:** {verified_status}\n" 148 | f"↯ **Flags:** {'Scam' if getattr(user, 'is_scam', False) else 'Fake' if getattr(user, 'is_fake', False) else 'Clean'}\n" 149 | f"↯ **Status:** {status}\n" 150 | f"↯ **Account Created On:** {account_created_str}\n" 151 | f"↯ **Account Age:** {account_age}" 152 | ) 153 | if user.is_bot: 154 | response = ( 155 | "✘《 **Bot Information** ↯ 》\n" 156 | f"↯ **Bot Name:** {user.first_name} {user.last_name or ''}\n" 157 | f"↯ **Bot ID:** `{user.id}`\n" 158 | f"↯ **Username:** @{user.username if user.username else 'None'}\n" 159 | f"↯ **Data Center:** {user.dc_id} ({dc_location})\n" 160 | f"↯ **Premium User:** {premium_status}\n" 161 | f"↯ **Verified:** {verified_status}\n" 162 | f"↯ **Flags:** {'Scam' if getattr(user, 'is_scam', False) else 'Fake' if getattr(user, 'is_fake', False) else 'Clean'}\n" 163 | f"↯ **Account Created On:** {account_created_str}\n" 164 | f"↯ **Account Age:** {account_age}" 165 | ) 166 | buttons = [ 167 | [InlineKeyboardButton("✘ Android Link ↯", url=f"tg://openmessage?user_id={user.id}"), InlineKeyboardButton("✘ iOS Link ↯", url=f"tg://user?id={user.id}")], 168 | [InlineKeyboardButton("✘ Permanent Link ↯", url=f"tg://user?id={user.id}")], 169 | ] 170 | await client.send_message(chat_id=message.chat.id, text=response, parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(buttons)) 171 | logger.info("Replied user info fetched successfully") 172 | elif len(message.command) > 1: 173 | # Extract username from the command 174 | logger.info("Extracting username from the command") 175 | username = message.command[1].strip('@').replace('https://', '').replace('http://', '').replace('t.me/', '').replace('/', '').replace(':', '') 176 | 177 | try: 178 | # First, attempt to get user or bot info 179 | logger.info(f"Fetching info for user or bot: {username}") 180 | user = await client.get_users(username) 181 | premium_status = "Yes" if user.is_premium else "No" 182 | dc_location = DC_LOCATIONS.get(user.dc_id, "Unknown") 183 | account_created = estimate_account_creation_date(user.id) 184 | account_created_str = account_created.strftime("%B %d, %Y") 185 | account_age = calculate_account_age(account_created) 186 | 187 | # Added verification and status 188 | verified_status = "Verified" if user.is_verified else "Not Verified" 189 | 190 | status = "⚪️ Unknown" 191 | if user.status: 192 | if user.status == UserStatus.ONLINE: 193 | status = "Online" 194 | elif user.status == UserStatus.OFFLINE: 195 | status = "Offline" 196 | elif user.status == UserStatus.RECENTLY: 197 | status = "Online" 198 | elif user.status == UserStatus.LAST_WEEK: 199 | status = "Last seen within a week" 200 | elif user.status == UserStatus.LAST_MONTH: 201 | status = "Last seen within a month" 202 | 203 | response = ( 204 | "✘《 **User Information** ↯ 》\n" 205 | f"✓ **Full Name:** {user.first_name} {user.last_name or ''}\n" 206 | f"✓ **ID:** `{user.id}`\n" 207 | f"✓ **Username:** @{user.username if user.username else 'None'}\n" 208 | f"✓ **Context ID:** `{user.id}`\n" 209 | f"✓ **Data Center:** {user.dc_id} ({dc_location})\n" 210 | f"✓ **Premium:** {premium_status}\n" 211 | f"✓ **Verification:** {verified_status}\n" 212 | f"✓ **Flags:** {'Scam' if getattr(user, 'is_scam', False) else 'Fake' if getattr(user, 'is_fake', False) else '✓ Clean'}\n" 213 | f"✓ **Status:** {status}\n" 214 | f"✓ **Account Created On:** {account_created_str}\n" 215 | f"✓ **Account Age:** {account_age}" 216 | ) 217 | if user.is_bot: 218 | response = ( 219 | "✘《 **Bot Information** ↯ 》\n" 220 | f"✓ **Bot Name:** {user.first_name} {user.last_name or ''}\n" 221 | f"✓ **Bot ID:** `{user.id}`\n" 222 | f"✓ **Username:** @{user.username if user.username else 'None'}\n" 223 | f"✓ **Data Center:** {user.dc_id} ({dc_location})\n" 224 | f"✓ **Premium:** {premium_status}\n" 225 | f"✓ **Verification:** {verified_status}\n" 226 | f"✓ **Flags:** {'Scam' if getattr(user, 'is_scam', False) else 'Fake' if getattr(user, 'is_fake', False) else '✓ Clean'}\n" 227 | f"✓ **Account Created On:** {account_created_str}\n" 228 | f"✓ **Account Age:** {account_age}" 229 | ) 230 | buttons = [ 231 | [InlineKeyboardButton("✘ Android Link ↯", url=f"tg://openmessage?user_id={user.id}"), InlineKeyboardButton("✘ iOS Link ↯", url=f"tg://user?id={user.id}")], 232 | [InlineKeyboardButton("✘ Permanent Link ↯", url=f"tg://user?id={user.id}")], 233 | ] 234 | await client.send_message(chat_id=message.chat.id, text=response, parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(buttons)) 235 | logger.info("User/bot info fetched successfully with buttons") 236 | except (PeerIdInvalid, UsernameNotOccupied, IndexError): 237 | logger.info(f"Username '{username}' not found as a user/bot. Checking for chat...") 238 | try: 239 | chat = await client.get_chat(username) 240 | dc_location = DC_LOCATIONS.get(chat.dc_id, "Unknown") 241 | response = ( 242 | f"✘《 **Chat Information** ↯ 》\n" 243 | f"✓ **{chat.title}**\n" 244 | f"✓ **ID:** `{chat.id}`\n" 245 | f"✓ **Type:** {'Supergroup' if chat.type == ChatType.SUPERGROUP else 'Group' if chat.type == ChatType.GROUP else 'Channel'}\n" 246 | f"✓ **Member count:** {chat.members_count if chat.members_count else 'Unknown'}" 247 | ) 248 | buttons = [ 249 | [InlineKeyboardButton("✘ Joining Link ↯", url=f"t.me/c/{str(chat.id).replace('-100', '')}/100"), InlineKeyboardButton("✘ Permanent Link ↯", url=f"t.me/c/{str(chat.id).replace('-100', '')}/100")], 250 | ] 251 | await client.send_message(chat_id=message.chat.id, text=response, parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(buttons)) 252 | logger.info("Chat info fetched successfully with buttons") 253 | except (ChannelInvalid, PeerIdInvalid): 254 | error_message = ( 255 | "**Looks Like I Don't Have Control Over The Channel**" 256 | if chat.type == ChatType.CHANNEL 257 | else "**Looks Like I Don't Have Control Over The Group**" 258 | ) 259 | await client.send_message(chat_id=message.chat.id, text=error_message, parse_mode=ParseMode.MARKDOWN) 260 | logger.error(f"Permission error: {error_message}") 261 | except Exception as e: 262 | logger.error(f"Error fetching chat info: {str(e)}") 263 | await client.send_message(chat_id=message.chat.id, text="**Looks Like I Don't Have Control Over The Group**", parse_mode=ParseMode.MARKDOWN) 264 | except Exception as e: 265 | logger.error(f"Error fetching user or bot info: {str(e)}") 266 | await client.send_message(chat_id=message.chat.id, text="**Looks Like I Don't Have Control Over The User**", parse_mode=ParseMode.MARKDOWN) 267 | except Exception as e: 268 | logger.error(f"Unhandled exception: {str(e)}") 269 | await client.send_message(chat_id=message.chat.id, text="**Sorry User Info Database API Error❌**", parse_mode=ParseMode.MARKDOWN) 270 | finally: 271 | await client.delete_messages(chat_id=message.chat.id, message_ids=progress_message.id) 272 | logger.info("Progress message deleted") 273 | except Exception as e: 274 | logger.error(f"Unhandled exception: {str(e)}") 275 | await client.send_message(chat_id=message.chat.id, text="**Sorry User Info Database API Error❌**", parse_mode=ParseMode.MARKDOWN) --------------------------------------------------------------------------------