├── runtime.txt ├── Procfile ├── heroku.yml ├── assets └── logo.jpg ├── plugins ├── route.py ├── __init__.py ├── channel.py ├── approve.py ├── json.py ├── banned.py ├── delete_files.py ├── broadcast.py ├── check_alive.py ├── inline.py ├── gfilters.py ├── genlink.py ├── connection.py ├── misc.py ├── index.py ├── filters.py ├── p_ttishow.py └── commands.py ├── requirements.txt ├── Dockerfile ├── start.sh ├── docker-compose.yml ├── render.yaml ├── logging.conf ├── sample_info.py ├── .gitignore ├── app.json ├── database ├── filters_mdb.py ├── gfilters_mdb.py ├── connections_mdb.py ├── users_chats_db.py └── ia_filterdb.py ├── bot.py ├── info.py ├── README.md ├── Script.py ├── utils.py └── LICENSE /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.8 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python3 bot.py 2 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile -------------------------------------------------------------------------------- /assets/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ritheshrkrm/PiroAutoFilterBot/HEAD/assets/logo.jpg -------------------------------------------------------------------------------- /plugins/route.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | 3 | routes = web.RouteTableDef() 4 | 5 | @routes.get("/", allow_head=True) 6 | async def root_route_handler(request): 7 | return web.json_response("PIROBOTS") -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from .route import routes 3 | 4 | 5 | async def web_server(): 6 | web_app = web.Application(client_max_size=30000000) 7 | web_app.add_routes(routes) 8 | return web_app -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrogram>=2.0.30 2 | tgcrypto 3 | pymongo[srv]==3.12.3 4 | motor==2.5.1 5 | marshmallow==3.14.1 6 | umongo==3.0.1 7 | requests 8 | bs4 9 | git+https://github.com/ritheshrkrm/cinemagoer 10 | datetime 11 | pytz 12 | aiohttp 13 | psutil==5.9.4 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-slim-buster 2 | 3 | RUN apt update && apt upgrade -y 4 | RUN apt install git -y 5 | COPY requirements.txt /requirements.txt 6 | 7 | RUN cd / 8 | RUN pip3 install -U pip && pip3 install -U -r requirements.txt 9 | WORKDIR /PiroAutoFilterBot 10 | 11 | COPY . . 12 | 13 | CMD ["python3", "bot.py"] -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | if [ -z $UPSTREAM_REPO ] 2 | then 3 | echo "Cloning main Repository" 4 | git clone https://github.com/ritheshrkrm/PiroAutoFilterBot.git /PiroAutoFilterBot 5 | else 6 | echo "Cloning Custom Repo from $UPSTREAM_REPO " 7 | git clone $UPSTREAM_REPO /PiroAutoFilterBot 8 | fi 9 | cd /PiroAutoFilterBot 10 | pip3 install -U -r requirements.txt 11 | echo "Starting PiroAutoFilterBot...." 12 | python3 bot.py 13 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.10" 2 | services: 3 | worker: 4 | build: . 5 | environment: 6 | BOT_TOKEN: $BOT_TOKEN 7 | API_ID: $API_ID 8 | API_HASH: $API_HASH 9 | CHANNELS: $CHANNELS 10 | ADMINS: $ADMINS 11 | LOG_CHANNEL: $LOG_CHANNEL 12 | DATABASE_NAME: $DATABASE_NAME 13 | DATABASE_URI: $DATABASE_URI 14 | HEROKU_API_KEY: $HEROKU_API_KEY 15 | -------------------------------------------------------------------------------- /render.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | # A Docker web service 3 | - type: web 4 | name: PiroAutoFilterBot 5 | env: python 6 | startCommand: python3 bot.py 7 | buildCommand: pip3 install -U -r requirements.txt 8 | repo: https://github/ritheshrkrm/PiroAutoFilterBot.git # optional 9 | region: oregon # optional (defaults to oregon) 10 | plan: free # optional (defaults to starter) 11 | branch: master # optional (defaults to master) 12 | numInstances: 1 # optional (defaults to 1) 13 | healthCheckPath: / 14 | 15 | #End of yaml 16 | -------------------------------------------------------------------------------- /plugins/channel.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from info import CHANNELS 3 | from database.ia_filterdb import save_file 4 | 5 | media_filter = filters.document | filters.video 6 | 7 | 8 | @Client.on_message(filters.chat(CHANNELS) & media_filter) 9 | async def media(bot, message): 10 | """Media Handler""" 11 | for file_type in ("document", "video"): 12 | media = getattr(message, file_type, None) 13 | if media is not None: 14 | break 15 | else: 16 | return 17 | 18 | media.file_type = file_type 19 | media.caption = message.caption 20 | await save_file(media) -------------------------------------------------------------------------------- /logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=consoleHandler,fileHandler 6 | 7 | [formatters] 8 | keys=consoleFormatter,fileFormatter 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=consoleHandler,fileHandler 13 | 14 | [handler_consoleHandler] 15 | class=StreamHandler 16 | level=INFO 17 | formatter=consoleFormatter 18 | args=(sys.stdout,) 19 | 20 | [handler_fileHandler] 21 | class=FileHandler 22 | level=ERROR 23 | formatter=fileFormatter 24 | args=('Logs.txt','w',) 25 | 26 | [formatter_consoleFormatter] 27 | format=%(asctime)s - %(lineno)d - %(name)s - %(module)s - %(levelname)s - %(message)s 28 | datefmt=%I:%M:%S %p 29 | 30 | [formatter_fileFormatter] 31 | format=[%(asctime)s:%(name)s:%(lineno)d:%(levelname)s] %(message)s 32 | datefmt=%m/%d/%Y %I:%M:%S %p -------------------------------------------------------------------------------- /sample_info.py: -------------------------------------------------------------------------------- 1 | # Bot information 2 | SESSION = 'Media_search' 3 | USER_SESSION = 'User_Bot' 4 | API_ID = 12345 5 | API_HASH = '0123456789abcdef0123456789abcdef' 6 | BOT_TOKEN = '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11' 7 | USERBOT_STRING_SESSION = '' 8 | 9 | # Bot settings 10 | CACHE_TIME = 300 11 | USE_CAPTION_FILTER = False 12 | 13 | # Admins, Channels & Users 14 | ADMINS = [12345789, 'admin123', 98765432] 15 | CHANNELS = [-10012345678, -100987654321, 'channelusername'] 16 | AUTH_USERS = [] 17 | AUTH_CHANNEL = None 18 | 19 | # MongoDB information 20 | DATABASE_URI = "mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb]?retryWrites=true&w=majority" 21 | DATABASE_NAME = 'Telegram' 22 | COLLECTION_NAME = 'channel_files' # If you are using the same database, then use different collection name for each bot 23 | 24 | 25 | -------------------------------------------------------------------------------- /plugins/approve.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client 2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 3 | from pyrogram.errors import UserIsBlocked, PeerIdInvalid 4 | 5 | 6 | @Client.on_chat_join_request() 7 | async def accept_request(client, r): 8 | 9 | rm = InlineKeyboardMarkup([[ 10 | InlineKeyboardButton("❤️‍🔥 𝖡𝖫𝖠𝖲𝖳𝖤𝖱 𝖧𝖴𝖡 ❤️‍🔥", url=f"https://t.me/blaster_hub"), 11 | InlineKeyboardButton("⚡𝖴𝗉𝖽𝖺𝗍𝖾𝗌 ⚡", url=f"https://t.me/piroxbots") 12 | ]]) 13 | 14 | try: 15 | await client.send_photo( 16 | r.from_user.id, 17 | 'https://graph.org/file/5cb80fa6096997b7226b3.jpg', 18 | f"**𝖧𝖾𝗅𝗅𝗈 {r.from_user.mention} 👻, 𝖶𝖾𝗅𝖼𝗈𝗆𝖾 𝖳𝗈 {r.chat.title}\n𝖸𝗈𝗎𝗋 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 𝖧𝖺𝗌 𝖡𝖾𝖾𝗇 𝖠𝗉𝗉𝗋𝗈𝗏𝖾𝖽...!!!**", 19 | reply_markup=rm) 20 | 21 | except UserIsBlocked: 22 | print("User blocked the bot") 23 | except PeerIdInvalid: 24 | print("Err") 25 | except Exception as e: 26 | print(f"#Error\n{str(e)}") 27 | 28 | await r.approve() 29 | -------------------------------------------------------------------------------- /plugins/json.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyrogram import Client, filters 3 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message, CallbackQuery 4 | 5 | @Client.on_message(filters.command(["json", 'js', 'showjson'])) 6 | async def jsonify(_, message): 7 | the_real_message = None 8 | reply_to_id = None 9 | 10 | if message.reply_to_message: 11 | the_real_message = message.reply_to_message 12 | else: 13 | the_real_message = message 14 | try: 15 | pk = InlineKeyboardMarkup( 16 | [ 17 | [ 18 | InlineKeyboardButton( 19 | text="🔐 𝖢𝗅𝗈𝗌𝖾", 20 | callback_data="close_data" 21 | ) 22 | ] 23 | ] 24 | ) 25 | await message.reply_text(f"{the_real_message}", reply_markup=pk, quote=True) 26 | except Exception as e: 27 | with open("json.text", "w+", encoding="utf8") as out_file: 28 | out_file.write(str(the_real_message)) 29 | reply_markup = InlineKeyboardMarkup( 30 | [ 31 | [ 32 | InlineKeyboardButton( 33 | text="🔐 𝖢𝗅𝗈𝗌𝖾", 34 | callback_data="close_data" 35 | ) 36 | ] 37 | ] 38 | ) 39 | await message.reply_document( 40 | document="json.text", 41 | caption=str(e), 42 | disable_notification=True, 43 | quote=True, 44 | reply_markup=reply_markup 45 | ) 46 | os.remove("json.text") 47 | 48 | -------------------------------------------------------------------------------- /plugins/banned.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from utils import temp 3 | from pyrogram.types import Message 4 | from database.users_chats_db import db 5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 6 | from info import SUPPORT_CHAT 7 | 8 | async def banned_users(_, client, message: Message): 9 | return ( 10 | message.from_user is not None or not message.sender_chat 11 | ) and message.from_user.id in temp.BANNED_USERS 12 | 13 | banned_user = filters.create(banned_users) 14 | 15 | async def disabled_chat(_, client, message: Message): 16 | return message.chat.id in temp.BANNED_CHATS 17 | 18 | disabled_group=filters.create(disabled_chat) 19 | 20 | 21 | @Client.on_message(filters.private & banned_user & filters.incoming) 22 | async def ban_reply(bot, message): 23 | ban = await db.get_ban_status(message.from_user.id) 24 | await message.reply(f'‼️Sorry Dude, You are Banned to use Me.‼️ \n\nBan Reason: {ban["ban_reason"]}') 25 | 26 | @Client.on_message(filters.group & disabled_group & filters.incoming) 27 | async def grp_bd(bot, message): 28 | buttons = [[ 29 | InlineKeyboardButton('🧩 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 🧩', url=f"https://t.me/{SUPPORT_CHAT}") 30 | ]] 31 | reply_markup=InlineKeyboardMarkup(buttons) 32 | vazha = await db.get_chat(message.chat.id) 33 | k = await message.reply( 34 | text=f"CHAT NOT ALLOWED 🐞\n\nMy admins has restricted me from working here ! If you want to know more about it contact 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 GROUP..\nReason : {vazha['reason']}.", 35 | reply_markup=reply_markup) 36 | try: 37 | await k.pin() 38 | except: 39 | pass 40 | await bot.leave_chat(message.chat.id) 41 | -------------------------------------------------------------------------------- /plugins/delete_files.py: -------------------------------------------------------------------------------- 1 | import re 2 | import logging 3 | from pyrogram import Client, filters 4 | from info import DELETE_CHANNELS 5 | from database.ia_filterdb import Media, unpack_new_file_id 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | media_filter = filters.document | filters.video | filters.audio 10 | 11 | 12 | @Client.on_message(filters.chat(DELETE_CHANNELS) & media_filter) 13 | async def deletemultiplemedia(bot, message): 14 | """Delete Multiple files from database""" 15 | 16 | for file_type in ("document", "video", "audio"): 17 | media = getattr(message, file_type, None) 18 | if media is not None: 19 | break 20 | else: 21 | return 22 | 23 | file_id, file_ref = unpack_new_file_id(media.file_id) 24 | 25 | result = await Media.collection.delete_one({ 26 | '_id': file_id, 27 | }) 28 | if result.deleted_count: 29 | logger.info('File is successfully deleted from database.') 30 | else: 31 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 32 | result = await Media.collection.delete_many({ 33 | 'file_name': file_name, 34 | 'file_size': media.file_size, 35 | 'mime_type': media.mime_type 36 | }) 37 | if result.deleted_count: 38 | logger.info('File is successfully deleted from database.') 39 | else: 40 | result = await Media.collection.delete_many({ 41 | 'file_name': media.file_name, 42 | 'file_size': media.file_size, 43 | 'mime_type': media.mime_type 44 | }) 45 | if result.deleted_count: 46 | logger.info('File is successfully deleted from database.') 47 | else: 48 | logger.info('File not found in database.') 49 | -------------------------------------------------------------------------------- /plugins/broadcast.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | import datetime 3 | import time 4 | from database.users_chats_db import db 5 | from info import ADMINS 6 | from utils import broadcast_messages, broadcast_messages_group 7 | import asyncio 8 | 9 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply) 10 | async def verupikkals(bot, message): 11 | users = await db.get_all_users() 12 | b_msg = message.reply_to_message 13 | sts = await message.reply_text( 14 | text='🔊 Broadcasting your messages...' 15 | ) 16 | start_time = time.time() 17 | total_users = await db.total_users_count() 18 | done = 0 19 | blocked = 0 20 | deleted = 0 21 | failed =0 22 | 23 | success = 0 24 | async for user in users: 25 | pti, sh = await broadcast_messages(int(user['id']), b_msg) 26 | if pti: 27 | success += 1 28 | elif pti == False: 29 | if sh == "Blocked": 30 | blocked+=1 31 | elif sh == "Deleted": 32 | deleted += 1 33 | elif sh == "Error": 34 | failed += 1 35 | done += 1 36 | await asyncio.sleep(2) 37 | if not done % 20: 38 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 39 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 40 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 41 | 42 | @Client.on_message(filters.command("group_broadcast") & filters.user(ADMINS) & filters.reply) 43 | async def broadcast_group(bot, message): 44 | groups = await db.get_all_chats() 45 | b_msg = message.reply_to_message 46 | sts = await message.reply_text( 47 | text='🔊 Broadcasting your messages To Groups...' 48 | ) 49 | start_time = time.time() 50 | total_groups = await db.total_chat_count() 51 | done = 0 52 | failed =0 53 | 54 | success = 0 55 | async for group in groups: 56 | pti, sh = await broadcast_messages_group(int(group['id']), b_msg) 57 | if pti: 58 | success += 1 59 | elif sh == "Error": 60 | failed += 1 61 | done += 1 62 | if not done % 20: 63 | await sts.edit(f"Broadcast in progress:\n\nTotal Groups {total_groups}\nCompleted: {done} / {total_groups}\nSuccess: {success}") 64 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 65 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Groups {total_groups}\nCompleted: {done} / {total_groups}\nSuccess: {success}") 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Personal files 2 | *.session 3 | *.session-journal 4 | .vscode 5 | *test*.py 6 | setup.cfg 7 | 8 | # Byte-compiled / optimized / DLL files 9 | __pycache__/ 10 | *.py[cod] 11 | *$py.class 12 | 13 | # C extensions 14 | *.so 15 | 16 | # Distribution / packaging 17 | .Python 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | share/python-wheels/ 31 | *.egg-info/ 32 | .installed.cfg 33 | *.egg 34 | MANIFEST 35 | 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | *.manifest 40 | *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .nox/ 50 | .coverage 51 | .coverage.* 52 | .cache 53 | nosetests.xml 54 | coverage.xml 55 | *.cover 56 | *.py,cover 57 | .hypothesis/ 58 | .pytest_cache/ 59 | cover/ 60 | 61 | # Translations 62 | *.mo 63 | *.pot 64 | 65 | # Django stuff: 66 | *.log 67 | local_settings.py 68 | db.sqlite3 69 | db.sqlite3-journal 70 | 71 | # Flask stuff: 72 | instance/ 73 | .webassets-cache 74 | 75 | # Scrapy stuff: 76 | .scrapy 77 | 78 | # Sphinx documentation 79 | docs/_build/ 80 | 81 | # PyBuilder 82 | .pybuilder/ 83 | target/ 84 | 85 | # Jupyter Notebook 86 | .ipynb_checkpoints 87 | 88 | # IPython 89 | profile_default/ 90 | ipython_config.py 91 | 92 | # pyenv 93 | # For a library or package, you might want to ignore these files since the code is 94 | # intended to run in multiple environments; otherwise, check them in: 95 | # .python-version 96 | 97 | # pipenv 98 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 99 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 100 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 101 | # install all needed dependencies. 102 | #Pipfile.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ 146 | config.py 147 | .goutputstream-VAFWB1 148 | result.json 149 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PiroAutoFilterBot", 3 | "description": "When you going to send file on telegram channel this bot will save that in database, So you can search that easily in inline mode", 4 | "stack": "container", 5 | "keywords": [ 6 | "telegram", 7 | "auto-filter", 8 | "filter", 9 | "best", 10 | "indian", 11 | "pyrogram", 12 | "media", 13 | "search", 14 | "channel", 15 | "index", 16 | "inline" 17 | ], 18 | "website": "https://github.com/ritheshrkrm/PiroAutoFilterBot", 19 | "repository": "https://github.com/ritheshrkrm/PiroAutoFilterBot", 20 | "env": { 21 | "BOT_TOKEN": { 22 | "description": "Your bot token.", 23 | "required": true 24 | }, 25 | "API_ID": { 26 | "description": "Get this value from https://my.telegram.org", 27 | "required": true 28 | }, 29 | "API_HASH": { 30 | "description": "Get this value from https://my.telegram.org", 31 | "required": true 32 | }, 33 | "CHANNELS": { 34 | "description": "Username or ID of channel or group. Separate multiple IDs by space.", 35 | "required": false 36 | }, 37 | "ADMINS": { 38 | "description": "Username or ID of Admin. Separate multiple Admins by space.", 39 | "required": true 40 | }, 41 | "PICS": { 42 | "description": "Add some telegraph link of pictures .", 43 | "required": false 44 | }, 45 | "LOG_CHANNEL": { 46 | "description": "Bot Logs,Give a channel id with -100xxxxxxx", 47 | "required": true 48 | }, 49 | "AUTH_USERS": { 50 | "description": "Username or ID of users to give access of inline search. Separate multiple users by space.\nLeave it empty if you don't want to restrict bot usage.", 51 | "required": false 52 | }, 53 | "AUTH_CHANNEL": { 54 | "description": "ID of channel.Make sure bot is admin in this channel. Without subscribing this channel users cannot use bot.", 55 | "required": false 56 | }, 57 | "DATABASE_URI": { 58 | "description": "mongoDB URI. Get this value from https://www.mongodb.com. For more help watch this video - https://youtu.be/dsuTn4qV2GA", 59 | "required": true 60 | }, 61 | "DATABASE_NAME": { 62 | "description": "Name of the database in mongoDB. For more help watch this video - https://youtu.be/dsuTn4qV2GA", 63 | "required": false 64 | }, 65 | "COLLECTION_NAME": { 66 | "description": "Name of the collections. Defaults to Telegram_files. If you are using the same database, then use different collection name for each bot", 67 | "value": "Telegram_files", 68 | "required": false 69 | } 70 | }, 71 | "addons": [], 72 | "buildpacks": [{ 73 | "url": "heroku/python" 74 | }], 75 | "formation": { 76 | "worker": { 77 | "quantity": 1, 78 | "size": "free" 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /database/filters_mdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from info import DATABASE_URI, DATABASE_NAME 3 | from pyrogram import enums 4 | import logging 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.ERROR) 7 | 8 | myclient = pymongo.MongoClient(DATABASE_URI) 9 | mydb = myclient[DATABASE_NAME] 10 | 11 | 12 | 13 | async def add_filter(grp_id, text, reply_text, btn, file, alert): 14 | mycol = mydb[str(grp_id)] 15 | # mycol.create_index([('text', 'text')]) 16 | 17 | data = { 18 | 'text':str(text), 19 | 'reply':str(reply_text), 20 | 'btn':str(btn), 21 | 'file':str(file), 22 | 'alert':str(alert) 23 | } 24 | 25 | try: 26 | mycol.update_one({'text': str(text)}, {"$set": data}, upsert=True) 27 | except: 28 | logger.exception('Some error occured!', exc_info=True) 29 | 30 | 31 | async def find_filter(group_id, name): 32 | mycol = mydb[str(group_id)] 33 | 34 | query = mycol.find( {"text":name}) 35 | # query = mycol.find( { "$text": {"$search": name}}) 36 | try: 37 | for file in query: 38 | reply_text = file['reply'] 39 | btn = file['btn'] 40 | fileid = file['file'] 41 | try: 42 | alert = file['alert'] 43 | except: 44 | alert = None 45 | return reply_text, btn, alert, fileid 46 | except: 47 | return None, None, None, None 48 | 49 | 50 | async def get_filters(group_id): 51 | mycol = mydb[str(group_id)] 52 | 53 | texts = [] 54 | query = mycol.find() 55 | try: 56 | for file in query: 57 | text = file['text'] 58 | texts.append(text) 59 | except: 60 | pass 61 | return texts 62 | 63 | 64 | async def delete_filter(message, text, group_id): 65 | mycol = mydb[str(group_id)] 66 | 67 | myquery = {'text':text } 68 | query = mycol.count_documents(myquery) 69 | if query == 1: 70 | mycol.delete_one(myquery) 71 | await message.reply_text( 72 | f"'`{text}`' deleted. I'll not respond to that filter anymore.", 73 | quote=True, 74 | parse_mode=enums.ParseMode.MARKDOWN 75 | ) 76 | else: 77 | await message.reply_text("Couldn't find that filter!", quote=True) 78 | 79 | 80 | async def del_all(message, group_id, title): 81 | if str(group_id) not in mydb.list_collection_names(): 82 | await message.edit_text(f"Nothing to remove in {title}!") 83 | return 84 | 85 | mycol = mydb[str(group_id)] 86 | try: 87 | mycol.drop() 88 | await message.edit_text(f"All filters from {title} has been removed") 89 | except: 90 | await message.edit_text("Couldn't remove all filters from group!") 91 | return 92 | 93 | 94 | async def count_filters(group_id): 95 | mycol = mydb[str(group_id)] 96 | 97 | count = mycol.count() 98 | return False if count == 0 else count 99 | 100 | 101 | async def filter_stats(): 102 | collections = mydb.list_collection_names() 103 | 104 | if "CONNECTION" in collections: 105 | collections.remove("CONNECTION") 106 | 107 | totalcount = 0 108 | for collection in collections: 109 | mycol = mydb[collection] 110 | count = mycol.count() 111 | totalcount += count 112 | 113 | totalcollections = len(collections) 114 | 115 | return totalcollections, totalcount 116 | -------------------------------------------------------------------------------- /database/gfilters_mdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from info import DATABASE_URI, DATABASE_NAME 3 | from pyrogram import enums 4 | import logging 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.ERROR) 7 | 8 | myclient = pymongo.MongoClient(DATABASE_URI) 9 | mydb = myclient[DATABASE_NAME] 10 | 11 | 12 | 13 | async def add_gfilter(gfilters, text, reply_text, btn, file, alert): 14 | mycol = mydb[str(gfilters)] 15 | 16 | data = { 17 | 'text':str(text), 18 | 'reply':str(reply_text), 19 | 'btn':str(btn), 20 | 'file':str(file), 21 | 'alert':str(alert) 22 | } 23 | 24 | try: 25 | mycol.update_one({'text': str(text)}, {"$set": data}, upsert=True) 26 | except: 27 | logger.exception('Some error occured!', exc_info=True) 28 | 29 | 30 | async def find_gfilter(gfilters, name): 31 | mycol = mydb[str(gfilters)] 32 | 33 | query = mycol.find( {"text":name}) 34 | # query = mycol.find( { "$text": {"$search": name}}) 35 | try: 36 | for file in query: 37 | reply_text = file['reply'] 38 | btn = file['btn'] 39 | fileid = file['file'] 40 | try: 41 | alert = file['alert'] 42 | except: 43 | alert = None 44 | return reply_text, btn, alert, fileid 45 | except: 46 | return None, None, None, None 47 | 48 | 49 | async def get_gfilters(gfilters): 50 | mycol = mydb[str(gfilters)] 51 | 52 | texts = [] 53 | query = mycol.find() 54 | try: 55 | for file in query: 56 | text = file['text'] 57 | texts.append(text) 58 | except: 59 | pass 60 | return texts 61 | 62 | 63 | async def delete_gfilter(message, text, gfilters): 64 | mycol = mydb[str(gfilters)] 65 | 66 | myquery = {'text':text } 67 | query = mycol.count_documents(myquery) 68 | if query == 1: 69 | mycol.delete_one(myquery) 70 | await message.reply_text( 71 | f"'`{text}`' deleted. I'll not respond to that gfilter anymore.", 72 | quote=True, 73 | parse_mode=enums.ParseMode.MARKDOWN 74 | ) 75 | else: 76 | await message.reply_text("Couldn't find that gfilter!", quote=True) 77 | 78 | async def del_allg(message, gfilters): 79 | if str(gfilters) not in mydb.list_collection_names(): 80 | await message.edit_text("Nothing to Remove !") 81 | return 82 | 83 | mycol = mydb[str(gfilters)] 84 | try: 85 | mycol.drop() 86 | await message.edit_text(f"All gfilters has been removed !") 87 | except: 88 | await message.edit_text("Couldn't remove all gfilters !") 89 | return 90 | 91 | async def count_gfilters(gfilters): 92 | mycol = mydb[str(gfilters)] 93 | 94 | count = mycol.count() 95 | return False if count == 0 else count 96 | 97 | 98 | async def gfilter_stats(): 99 | collections = mydb.list_collection_names() 100 | 101 | if "CONNECTION" in collections: 102 | collections.remove("CONNECTION") 103 | 104 | totalcount = 0 105 | for collection in collections: 106 | mycol = mydb[collection] 107 | count = mycol.count() 108 | totalcount += count 109 | 110 | totalcollections = len(collections) 111 | 112 | return totalcollections, totalcount 113 | -------------------------------------------------------------------------------- /database/connections_mdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | 3 | from info import DATABASE_URI, DATABASE_NAME 4 | 5 | import logging 6 | logger = logging.getLogger(__name__) 7 | logger.setLevel(logging.ERROR) 8 | 9 | myclient = pymongo.MongoClient(DATABASE_URI) 10 | mydb = myclient[DATABASE_NAME] 11 | mycol = mydb['CONNECTION'] 12 | 13 | 14 | async def add_connection(group_id, user_id): 15 | query = mycol.find_one( 16 | { "_id": user_id }, 17 | { "_id": 0, "active_group": 0 } 18 | ) 19 | if query is not None: 20 | group_ids = [x["group_id"] for x in query["group_details"]] 21 | if group_id in group_ids: 22 | return False 23 | 24 | group_details = { 25 | "group_id" : group_id 26 | } 27 | 28 | data = { 29 | '_id': user_id, 30 | 'group_details' : [group_details], 31 | 'active_group' : group_id, 32 | } 33 | 34 | if mycol.count_documents( {"_id": user_id} ) == 0: 35 | try: 36 | mycol.insert_one(data) 37 | return True 38 | except: 39 | logger.exception('Some error occurred!', exc_info=True) 40 | 41 | else: 42 | try: 43 | mycol.update_one( 44 | {'_id': user_id}, 45 | { 46 | "$push": {"group_details": group_details}, 47 | "$set": {"active_group" : group_id} 48 | } 49 | ) 50 | return True 51 | except: 52 | logger.exception('Some error occurred!', exc_info=True) 53 | 54 | 55 | async def active_connection(user_id): 56 | 57 | query = mycol.find_one( 58 | { "_id": user_id }, 59 | { "_id": 0, "group_details": 0 } 60 | ) 61 | if not query: 62 | return None 63 | 64 | group_id = query['active_group'] 65 | return int(group_id) if group_id != None else None 66 | 67 | 68 | async def all_connections(user_id): 69 | query = mycol.find_one( 70 | { "_id": user_id }, 71 | { "_id": 0, "active_group": 0 } 72 | ) 73 | if query is not None: 74 | return [x["group_id"] for x in query["group_details"]] 75 | else: 76 | return None 77 | 78 | 79 | async def if_active(user_id, group_id): 80 | query = mycol.find_one( 81 | { "_id": user_id }, 82 | { "_id": 0, "group_details": 0 } 83 | ) 84 | return query is not None and query['active_group'] == group_id 85 | 86 | 87 | async def make_active(user_id, group_id): 88 | update = mycol.update_one( 89 | {'_id': user_id}, 90 | {"$set": {"active_group" : group_id}} 91 | ) 92 | return update.modified_count != 0 93 | 94 | 95 | async def make_inactive(user_id): 96 | update = mycol.update_one( 97 | {'_id': user_id}, 98 | {"$set": {"active_group" : None}} 99 | ) 100 | return update.modified_count != 0 101 | 102 | 103 | async def delete_connection(user_id, group_id): 104 | 105 | try: 106 | update = mycol.update_one( 107 | {"_id": user_id}, 108 | {"$pull" : { "group_details" : {"group_id":group_id} } } 109 | ) 110 | if update.modified_count == 0: 111 | return False 112 | query = mycol.find_one( 113 | { "_id": user_id }, 114 | { "_id": 0 } 115 | ) 116 | if len(query["group_details"]) >= 1: 117 | if query['active_group'] == group_id: 118 | prvs_group_id = query["group_details"][len(query["group_details"]) - 1]["group_id"] 119 | 120 | mycol.update_one( 121 | {'_id': user_id}, 122 | {"$set": {"active_group" : prvs_group_id}} 123 | ) 124 | else: 125 | mycol.update_one( 126 | {'_id': user_id}, 127 | {"$set": {"active_group" : None}} 128 | ) 129 | return True 130 | except Exception as e: 131 | logger.exception(f'Some error occurred! {e}', exc_info=True) 132 | return False 133 | 134 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | 4 | # Get logging configurations 5 | logging.config.fileConfig('logging.conf') 6 | logging.getLogger().setLevel(logging.INFO) 7 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 8 | logging.getLogger("imdbpy").setLevel(logging.ERROR) 9 | 10 | from pyrogram import Client, __version__ 11 | from pyrogram.raw.all import layer 12 | from database.ia_filterdb import Media 13 | from database.users_chats_db import db 14 | from info import SESSION, API_ID, API_HASH, BOT_TOKEN, LOG_STR, LOG_CHANNEL, PORT ,SUPPORT_CHAT_ID 15 | from utils import temp 16 | from typing import Union, Optional, AsyncGenerator 17 | from pyrogram import types 18 | from Script import script 19 | from datetime import date, datetime 20 | import pytz 21 | from aiohttp import web 22 | from plugins import web_server 23 | 24 | class Bot(Client): 25 | 26 | def __init__(self): 27 | super().__init__( 28 | name=SESSION, 29 | api_id=API_ID, 30 | api_hash=API_HASH, 31 | bot_token=BOT_TOKEN, 32 | workers=50, 33 | plugins={"root": "plugins"}, 34 | sleep_threshold=5, 35 | ) 36 | 37 | async def start(self): 38 | b_users, b_chats = await db.get_banned() 39 | temp.BANNED_USERS = b_users 40 | temp.BANNED_CHATS = b_chats 41 | await super().start() 42 | await Media.ensure_indexes() 43 | me = await self.get_me() 44 | temp.ME = me.id 45 | temp.U_NAME = me.username 46 | temp.B_NAME = me.first_name 47 | self.username = '@' + me.username 48 | logging.info(f"{me.first_name} with for Pyrogram v{__version__} (Layer {layer}) started on {me.username}.") 49 | logging.info(LOG_STR) 50 | logging.info(script.LOGO) 51 | tz = pytz.timezone('Asia/Kolkata') 52 | today = date.today() 53 | now = datetime.now(tz) 54 | time = now.strftime("%H:%M:%S %p") 55 | await self.send_message(chat_id=LOG_CHANNEL, text=script.RESTART_TXT.format(today, time)) 56 | await self.send_message(chat_id=SUPPORT_CHAT_ID, text=script.RESTART_GC_TXT.format(today, time)) 57 | app = web.AppRunner(await web_server()) 58 | await app.setup() 59 | bind_address = "0.0.0.0" 60 | await web.TCPSite(app, bind_address, PORT).start() 61 | 62 | async def stop(self, *args): 63 | await super().stop() 64 | logging.info("Bot stopped. Bye.") 65 | 66 | async def iter_messages( 67 | self, 68 | chat_id: Union[int, str], 69 | limit: int, 70 | offset: int = 0, 71 | ) -> Optional[AsyncGenerator["types.Message", None]]: 72 | """Iterate through a chat sequentially. 73 | This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_messages` in a loop, thus saving 74 | you from the hassle of setting up boilerplate code. It is useful for getting the whole chat messages with a 75 | single call. 76 | Parameters: 77 | chat_id (``int`` | ``str``): 78 | Unique identifier (int) or username (str) of the target chat. 79 | For your personal cloud (Saved Messages) you can simply use "me" or "self". 80 | For a contact that exists in your Telegram address book you can use his phone number (str). 81 | 82 | limit (``int``): 83 | Identifier of the last message to be returned. 84 | 85 | offset (``int``, *optional*): 86 | Identifier of the first message to be returned. 87 | Defaults to 0. 88 | Returns: 89 | ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. 90 | Example: 91 | .. code-block:: python 92 | for message in app.iter_messages("pyrogram", 1, 15000): 93 | print(message.text) 94 | """ 95 | current = offset 96 | while True: 97 | new_diff = min(200, limit - current) 98 | if new_diff <= 0: 99 | return 100 | messages = await self.get_messages(chat_id, list(range(current, current+new_diff+1))) 101 | for message in messages: 102 | yield message 103 | current += 1 104 | 105 | 106 | app = Bot() 107 | app.run() 108 | -------------------------------------------------------------------------------- /plugins/check_alive.py: -------------------------------------------------------------------------------- 1 | import random 2 | import re, asyncio, time, shutil, psutil, os, sys 3 | from pyrogram import Client, filters, enums 4 | from pyrogram.types import * 5 | from info import BOT_START_TIME, ADMINS 6 | from utils import humanbytes 7 | 8 | CMD = ["/", "."] 9 | 10 | @Client.on_message(filters.command("alive", CMD)) 11 | async def check_alive(_, message): 12 | await message.reply_text("𝖡𝗎𝖽𝖽𝗒 𝖨𝖺𝗆 𝖠𝗅𝗂𝗏𝖾 :) 𝖧𝗂𝗍 /start \n\n𝖧𝗂𝗍 /help 𝖥𝗈𝗋 𝖧𝖾𝗅𝗉 ;)\n\n\n𝖧𝗂𝗍 /ping 𝖳𝗈 𝖢𝗁𝖾𝖼𝗄 𝖡𝗈𝗍 𝖯𝗂𝗇𝗀 😁") 13 | 14 | @Client.on_message(filters.command("help", CMD)) 15 | async def help(_, message): 16 | await message.reply_text("𝖧𝗂𝗍 /movie 𝖥𝗈𝗋 𝖬𝗈𝗏𝗂𝖾 𝖲𝖾𝖺𝗋𝖼𝗁 𝖱𝗎𝗅𝖾𝗌 📃\n\n𝖧𝗂𝗍 /series 𝖥𝗈𝗋 𝖲𝖾𝗋𝗂𝖾𝗌 𝖲𝖾𝖺𝗋𝖼𝗁 𝖱𝗎𝗅𝖾𝗌 📃\n\n\n𝖧𝗂𝗍 /tutorial 𝖥𝗈𝗋 𝖯𝗋𝗈𝗉𝖾𝗋 𝖳𝗎𝗍𝗈𝗋𝗂𝖺𝗅 𝖵𝗂𝖽𝖾𝗈𝗌 🤗") 17 | 18 | 19 | @Client.on_message(filters.command("movie", CMD)) 20 | async def movie(_, message): 21 | await message.reply_text("⚠️❗️ 𝗠𝗼𝘃𝗶𝗲 𝗥𝗲𝗾𝘂𝗲𝘀𝘁 𝗙𝗼𝗿𝗺𝗮𝘁 ❗️⚠️\n\n📝 𝖬𝗈𝗏𝗂𝖾 𝖭𝖺𝗆𝖾, 𝖸𝖾𝖺𝗋,(𝖨𝖿 𝗒𝗈𝗎 𝖪𝗇𝗈𝗐) 𝖶𝗂𝗍𝗁 𝖢𝗈𝗋𝗋𝖾𝖼𝗍 𝖲𝗉𝖾𝗅𝗅𝗂𝗇𝗀 📚\n\n🗣 𝖨𝖿 𝖨𝗍 𝗂𝗌 𝖺 𝖥𝗂𝗅𝗆 𝖲𝖾𝗋𝗂𝖾𝗌. 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 𝖮𝗇𝖾 𝖡𝗒 𝖮𝗇𝖾 𝖶𝗂𝗍𝗁 𝖯𝗋𝗈𝗉𝖾𝗋 𝖭𝖺𝗆𝖾 🧠\n\n🖇𝐄𝐱𝐚𝐦𝐩𝐥𝐞:\n\n• Robin Hood ✅\n• Robin Hood 2010✅\n• Kurup 2021 Kan✅ \n• Harry Potter and the Philosophers Stone✅\n• Harry Potter and the Prisoner of Azkaban✅\n\n🥱 𝖥𝗈𝗋 𝖫𝖺𝗇𝗀𝗎𝖺𝗀𝖾 𝖠𝗎𝖽𝗂𝗈𝗌 - 𝖪𝖺𝗇 𝖿𝗈𝗋 𝖪𝖺𝗇𝗇𝖺𝖽𝖺, 𝖬𝖺𝗅 - 𝖬𝖺𝗅𝖺𝗒𝖺𝗅𝖺𝗆, 𝖳𝖺𝗆 - 𝖳𝖺𝗆𝗂𝗅\n\n🔎 𝖴𝗌𝖾 𝖥𝗂𝗋𝗌𝗍 3 𝖫𝖾𝗍𝗍𝖾𝗋𝗌 𝖮𝖿 𝖫𝖺𝗇𝗀𝗎𝖺𝗀𝖾 𝖥𝗈𝗋 𝖠𝗎𝖽𝗂𝗈𝗌 [𝖪𝖺𝗇 𝖳𝖺𝗆 𝖳𝖾𝗅 𝖬𝖺𝗅 𝖧𝗂𝗇 𝖲𝗉𝖺 𝖤𝗇𝗀 𝖪𝗈𝗋 𝖾𝗍𝖼...]\n\n❌ [𝗗𝗼𝗻𝘁 𝗨𝘀𝗲 𝘄𝗼𝗿𝗱𝘀 𝗟𝗶𝗸𝗲 𝗗𝘂𝗯𝗯𝗲𝗱/𝗠𝗼𝘃𝗶𝗲𝘀/𝗦𝗲𝗻𝗱/𝗛𝗗 , . : - 𝗲𝘁𝗰] ❌") 22 | 23 | @Client.on_message(filters.command("series", CMD)) 24 | async def series(_, message): 25 | await message.reply_text("⚠️❗️ 𝗦𝗲𝗿𝗶𝗲𝘀 𝗥𝗲𝗾𝘂𝗲𝘀𝘁 𝗙𝗼𝗿𝗺𝗮𝘁 ❗️⚠️\n\n🗣 𝖲𝖾𝗋𝗂𝖾𝗌 𝖭𝖺𝗆𝖾,𝖲𝖾𝖺𝗌𝗈𝗇 (𝖶𝗁𝗂𝖼𝗁 𝖲𝖾𝖺𝗌𝗈𝗇 𝗒𝗈𝗎 𝗐𝖺𝗇𝗍) 🧠\n\n🖇𝐄𝐱𝐚𝐦𝐩𝐥𝐞: \n\n• Game Of Thrones S03𝖤02 720𝗉✅\n• Sex Education S02 720p✅ \n• Breaking Bad S01E05✅ \n• Prison Break 1080p✅ \n• Witcher S02✅\n\n🥱 𝖥𝗈𝗋 𝖲𝖾𝖺𝗌𝗈𝗇 𝖬𝖾𝗇𝗍𝗂𝗈𝗇 𝖠𝗌 𝖲01 𝖥𝗈𝗋 𝖲𝖾𝖺𝗌𝗈𝗇 1, 𝖲02 𝖥𝗈𝗋 𝖲𝖾𝖺𝗌𝗈𝗇 2 𝖾𝗍𝖼 [𝖲03,𝖲04 ,𝖲06,𝖲10,𝖲17] 𝖦𝗈𝖾𝗌 𝖫𝗂𝗄𝖾 𝖳𝗁𝖺𝗍\n\n🔎 𝖥𝗈𝗋 𝖤𝗉𝗂𝗌𝗈𝖽𝖾 𝖬𝖾𝗇𝗍𝗂𝗈𝗇 𝖠𝗌 𝖤𝗉01 𝖥𝗈𝗋 𝖤𝗉𝗂𝗌𝗈𝖽𝖾 1, 𝖤𝗉02 𝖥𝗈𝗋 𝖤𝗉𝗂𝗌𝗈𝖽𝖾 2 𝖾𝗍𝖼 [𝖤𝗉03,𝖤𝗉07,𝖤𝗉17,𝖤𝗉21] 𝖦𝗈'𝗌 𝖫𝗂𝗄𝖾 𝖳𝗁𝖺𝗍 \n\n❌ [𝗗𝗼𝗻𝘁 𝗨𝘀𝗲 𝘄𝗼𝗿𝗱𝘀 𝗟𝗶𝗸𝗲 𝗦𝗲𝗮𝘀𝗼𝗻/𝗘𝗽𝗶𝘀𝗼𝗱𝗲/𝗦𝗲𝗿𝗶𝗲𝘀 , . : - 𝗲𝘁𝗰] ❌") 26 | 27 | @Client.on_message(filters.command("tutorial", CMD)) 28 | async def tutorial(_, message): 29 | await message.reply_text("𝖢𝗁𝖾𝖼𝗄𝗈𝗎𝗍 @piro_tuts 𝖥𝗈𝗋 𝖳𝗎𝗍𝗈𝗋𝗂𝖺𝗅𝗌 😎") 30 | 31 | @Client.on_message(filters.command("ping", CMD)) 32 | async def ping(_, message): 33 | start_t = time.time() 34 | rm = await message.reply_text("...........") 35 | end_t = time.time() 36 | time_taken_s = (end_t - start_t) * 1000 37 | await rm.edit(f"𝖯𝗂𝗇𝗀!\n{time_taken_s:.3f} ms") 38 | 39 | @Client.on_message(filters.command("status")) 40 | async def stats(bot, update): 41 | currentTime = time.strftime("%Hh%Mm%Ss", time.gmtime(time.time() - BOT_START_TIME)) 42 | total, used, free = shutil.disk_usage(".") 43 | total = humanbytes(total) 44 | used = humanbytes(used) 45 | free = humanbytes(free) 46 | cpu_usage = psutil.cpu_percent() 47 | ram_usage = psutil.virtual_memory().percent 48 | disk_usage = psutil.disk_usage('/').percent 49 | 50 | ms_g = f"""⚙️ 𝖡𝗈𝗍 𝖲𝗍𝖺𝗍𝗎𝗌 51 | 52 | 🕔 𝖴𝗉𝗍𝗂𝗆𝖾: {currentTime} 53 | 🛠 𝖢𝖯𝖴 𝖴𝗌𝖺𝗀𝖾: {cpu_usage}% 54 | 🗜 𝖱𝖠𝖬 𝖴𝗌𝖺𝗀𝖾: {ram_usage}% 55 | 🗂 𝖳𝗈𝗍𝖺𝗅 𝖣𝗂𝗌𝗄 𝖲𝗉𝖺𝖼𝖾: {total} 56 | 🗳 𝖴𝗌𝖾𝖽 𝖲𝗉𝖺𝖼𝖾: {used} ({disk_usage}%) 57 | 📝 𝖥𝗋𝖾𝖾 𝖲𝗉𝖺𝖼𝖾: {free} """ 58 | 59 | msg = await bot.send_message(chat_id=update.chat.id, text="__𝖯𝗋𝗈𝖼𝖾𝗌𝗌𝗂𝗇𝗀...__", parse_mode=enums.ParseMode.MARKDOWN) 60 | await msg.edit_text(text=ms_g, parse_mode=enums.ParseMode.HTML) 61 | 62 | @Client.on_message(filters.command("restart") & filters.user(ADMINS)) 63 | async def stop_button(bot, message): 64 | msg = await bot.send_message(text="**𝖡𝗈𝗍 𝖨𝗌 𝖱𝖾𝗌𝗍𝖺𝗋𝗍𝗂𝗇𝗀...🪄**", chat_id=message.chat.id) 65 | await asyncio.sleep(3) 66 | await msg.edit("**𝖡𝗈𝗍 𝖱𝖾𝗌𝗍𝖺𝗋𝗍𝖾𝖽 𝖲𝗎𝖼𝖼𝖾𝗌𝗌𝖿𝗎𝗅𝗅𝗒 ! 𝖱𝖾𝖺𝖽𝗒 𝖳𝗈 𝖬𝗈𝗏𝖾 𝖮𝗇 💯**") 67 | os.execl(sys.executable, sys.executable, *sys.argv) -------------------------------------------------------------------------------- /database/users_chats_db.py: -------------------------------------------------------------------------------- 1 | import motor.motor_asyncio 2 | from info import DATABASE_NAME, DATABASE_URI, IMDB, IMDB_TEMPLATE, MELCOW_NEW_USERS, P_TTI_SHOW_OFF, SINGLE_BUTTON, SPELL_CHECK_REPLY, PROTECT_CONTENT, AUTO_DELETE, AUTO_FFILTER, MAX_BTN 3 | 4 | class Database: 5 | 6 | def __init__(self, uri, database_name): 7 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri) 8 | self.db = self._client[database_name] 9 | self.col = self.db.users 10 | self.grp = self.db.groups 11 | 12 | 13 | def new_user(self, id, name): 14 | return dict( 15 | id = id, 16 | name = name, 17 | ban_status=dict( 18 | is_banned=False, 19 | ban_reason="", 20 | ), 21 | ) 22 | 23 | 24 | def new_group(self, id, title): 25 | return dict( 26 | id = id, 27 | title = title, 28 | chat_status=dict( 29 | is_disabled=False, 30 | reason="", 31 | ), 32 | ) 33 | 34 | async def add_user(self, id, name): 35 | user = self.new_user(id, name) 36 | await self.col.insert_one(user) 37 | 38 | async def is_user_exist(self, id): 39 | user = await self.col.find_one({'id':int(id)}) 40 | return bool(user) 41 | 42 | async def total_users_count(self): 43 | count = await self.col.count_documents({}) 44 | return count 45 | 46 | async def remove_ban(self, id): 47 | ban_status = dict( 48 | is_banned=False, 49 | ban_reason='' 50 | ) 51 | await self.col.update_one({'id': id}, {'$set': {'ban_status': ban_status}}) 52 | 53 | async def ban_user(self, user_id, ban_reason="No Reason"): 54 | ban_status = dict( 55 | is_banned=True, 56 | ban_reason=ban_reason 57 | ) 58 | await self.col.update_one({'id': user_id}, {'$set': {'ban_status': ban_status}}) 59 | 60 | async def get_ban_status(self, id): 61 | default = dict( 62 | is_banned=False, 63 | ban_reason='' 64 | ) 65 | user = await self.col.find_one({'id':int(id)}) 66 | if not user: 67 | return default 68 | return user.get('ban_status', default) 69 | 70 | async def get_all_users(self): 71 | return self.col.find({}) 72 | 73 | 74 | async def delete_user(self, user_id): 75 | await self.col.delete_many({'id': int(user_id)}) 76 | 77 | 78 | async def get_banned(self): 79 | users = self.col.find({'ban_status.is_banned': True}) 80 | chats = self.grp.find({'chat_status.is_disabled': True}) 81 | b_chats = [chat['id'] async for chat in chats] 82 | b_users = [user['id'] async for user in users] 83 | return b_users, b_chats 84 | 85 | 86 | 87 | async def add_chat(self, chat, title): 88 | chat = self.new_group(chat, title) 89 | await self.grp.insert_one(chat) 90 | 91 | 92 | async def get_chat(self, chat): 93 | chat = await self.grp.find_one({'id':int(chat)}) 94 | return False if not chat else chat.get('chat_status') 95 | 96 | 97 | async def re_enable_chat(self, id): 98 | chat_status=dict( 99 | is_disabled=False, 100 | reason="", 101 | ) 102 | await self.grp.update_one({'id': int(id)}, {'$set': {'chat_status': chat_status}}) 103 | 104 | async def update_settings(self, id, settings): 105 | await self.grp.update_one({'id': int(id)}, {'$set': {'settings': settings}}) 106 | 107 | 108 | async def get_settings(self, id): 109 | default = { 110 | 'button': SINGLE_BUTTON, 111 | 'botpm': P_TTI_SHOW_OFF, 112 | 'file_secure': PROTECT_CONTENT, 113 | 'imdb': IMDB, 114 | 'spell_check': SPELL_CHECK_REPLY, 115 | 'welcome': MELCOW_NEW_USERS, 116 | 'auto_delete': AUTO_DELETE, 117 | 'auto_ffilter': AUTO_FFILTER, 118 | 'max_btn': MAX_BTN, 119 | 'template': IMDB_TEMPLATE 120 | } 121 | chat = await self.grp.find_one({'id':int(id)}) 122 | if chat: 123 | return chat.get('settings', default) 124 | return default 125 | 126 | 127 | async def disable_chat(self, chat, reason="No Reason"): 128 | chat_status=dict( 129 | is_disabled=True, 130 | reason=reason, 131 | ) 132 | await self.grp.update_one({'id': int(chat)}, {'$set': {'chat_status': chat_status}}) 133 | 134 | 135 | async def total_chat_count(self): 136 | count = await self.grp.count_documents({}) 137 | return count 138 | 139 | 140 | async def get_all_chats(self): 141 | return self.grp.find({}) 142 | 143 | 144 | async def get_db_size(self): 145 | return (await self.db.command("dbstats"))['dataSize'] 146 | 147 | 148 | db = Database(DATABASE_URI, DATABASE_NAME) 149 | -------------------------------------------------------------------------------- /plugins/inline.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyrogram import Client, emoji, filters 3 | from pyrogram.errors.exceptions.bad_request_400 import QueryIdInvalid 4 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, InlineQueryResultCachedDocument, InlineQuery 5 | from database.ia_filterdb import get_search_results 6 | from utils import is_subscribed, get_size, temp 7 | from info import CACHE_TIME, AUTH_USERS, AUTH_CHANNEL, CUSTOM_FILE_CAPTION 8 | from database.connections_mdb import active_connection 9 | 10 | logger = logging.getLogger(__name__) 11 | cache_time = 0 if AUTH_USERS or AUTH_CHANNEL else CACHE_TIME 12 | 13 | async def inline_users(query: InlineQuery): 14 | if AUTH_USERS: 15 | if query.from_user and query.from_user.id in AUTH_USERS: 16 | return True 17 | else: 18 | return False 19 | if query.from_user and query.from_user.id not in temp.BANNED_USERS: 20 | return True 21 | return False 22 | 23 | @Client.on_inline_query() 24 | async def answer(bot, query): 25 | """𝖲𝗁𝗈𝗐 𝖲𝖾𝖺𝗋𝖼𝗁 𝖱𝖾𝗌𝗎𝗅𝗍𝗌 𝖥𝗈𝗋 𝖦𝗂𝗏𝖾𝗇 𝖨𝗇𝗅𝗂𝗇𝖾 𝖰𝗎𝖾𝗋𝗒""" 26 | chat_id = await active_connection(str(query.from_user.id)) 27 | 28 | if not await inline_users(query): 29 | await query.answer(results=[], 30 | cache_time=0, 31 | switch_pm_text='okDa', 32 | switch_pm_parameter="hehe") 33 | return 34 | 35 | if AUTH_CHANNEL and not await is_subscribed(bot, query): 36 | await query.answer(results=[], 37 | cache_time=0, 38 | switch_pm_text='𝖸𝗈𝗎 𝖧𝖺𝗏𝖾 𝖳𝗈 𝖲𝗎𝖻𝗌𝖼𝗋𝗂𝖻𝖾 𝖬𝗒 𝖢𝗁𝖺𝗇𝗇𝖾𝗅 𝖳𝗈 𝖴𝗌𝖾 𝖬𝖾 :)', 39 | switch_pm_parameter="subscribe") 40 | return 41 | 42 | results = [] 43 | if '|' in query.query: 44 | string, file_type = query.query.split('|', maxsplit=1) 45 | string = string.strip() 46 | file_type = file_type.strip().lower() 47 | else: 48 | string = query.query.strip() 49 | file_type = None 50 | 51 | offset = int(query.offset or 0) 52 | reply_markup = get_reply_markup(query=string) 53 | files, next_offset, total = await get_search_results( 54 | chat_id, 55 | string, 56 | file_type=file_type, 57 | max_results=10, 58 | offset=offset) 59 | 60 | for file in files: 61 | title=file.file_name 62 | size=get_size(file.file_size) 63 | f_caption=file.caption 64 | if CUSTOM_FILE_CAPTION: 65 | try: 66 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 67 | except Exception as e: 68 | logger.exception(e) 69 | f_caption=f_caption 70 | if f_caption is None: 71 | f_caption = f"{file.file_name}" 72 | results.append( 73 | InlineQueryResultCachedDocument( 74 | title=file.file_name, 75 | document_file_id=file.file_id, 76 | caption=f_caption, 77 | description=f'Size: {get_size(file.file_size)}\nType: {file.file_type}', 78 | reply_markup=reply_markup)) 79 | 80 | if results: 81 | switch_pm_text = f"{emoji.FILE_FOLDER} 𝖧𝖾𝗋𝖾 𝖨𝗌 𝖳𝗁𝖾 𝖱𝖾𝗌𝗎𝗅𝗍𝗌 " 82 | if string: 83 | switch_pm_text += f" for {string}" 84 | try: 85 | await query.answer(results=results, 86 | is_personal = True, 87 | cache_time=cache_time, 88 | switch_pm_text=switch_pm_text, 89 | switch_pm_parameter="start", 90 | next_offset=str(next_offset)) 91 | except QueryIdInvalid: 92 | pass 93 | except Exception as e: 94 | logging.exception(str(e)) 95 | else: 96 | switch_pm_text = f'{emoji.CROSS_MARK} 𝖭𝗈 𝖱𝖾𝗌𝗎𝗅𝗍𝗌 𝖥𝗈𝗎𝗇𝖽' 97 | if string: 98 | switch_pm_text += f' for "{string}"' 99 | 100 | await query.answer(results=[], 101 | is_personal = True, 102 | cache_time=cache_time, 103 | switch_pm_text=switch_pm_text, 104 | switch_pm_parameter="okay") 105 | 106 | 107 | def get_reply_markup(query): 108 | buttons = [ 109 | [ 110 | InlineKeyboardButton('🔎 𝖲𝖾𝖺𝗋𝖼𝗁 𝖠𝗀𝖺𝗂𝗇', switch_inline_query_current_chat=query), 111 | InlineKeyboardButton('⚡𝖴𝗉𝖽𝖺𝗍𝖾𝗌 ⚡', url="https://t.me/piroxbots") 112 | ] 113 | ] 114 | return InlineKeyboardMarkup(buttons) 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /plugins/gfilters.py: -------------------------------------------------------------------------------- 1 | import io 2 | from pyrogram import filters, Client, enums 3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 4 | from database.gfilters_mdb import( 5 | add_gfilter, 6 | get_gfilters, 7 | delete_gfilter, 8 | count_gfilters 9 | ) 10 | 11 | from database.connections_mdb import active_connection 12 | from utils import get_file_id, gfilterparser, split_quotes 13 | from info import ADMINS 14 | 15 | 16 | @Client.on_message(filters.command(['gfilter', 'addg']) & filters.incoming & filters.user(ADMINS)) 17 | async def addgfilter(client, message): 18 | args = message.text.html.split(None, 1) 19 | 20 | if len(args) < 2: 21 | await message.reply_text("Command Incomplete :(", quote=True) 22 | return 23 | 24 | extracted = split_quotes(args[1]) 25 | text = extracted[0].lower() 26 | 27 | if not message.reply_to_message and len(extracted) < 2: 28 | await message.reply_text("Add some content to save your filter!", quote=True) 29 | return 30 | 31 | if (len(extracted) >= 2) and not message.reply_to_message: 32 | reply_text, btn, alert = gfilterparser(extracted[1], text) 33 | fileid = None 34 | if not reply_text: 35 | await message.reply_text("You cannot have buttons alone, give some text to go with it!", quote=True) 36 | return 37 | 38 | elif message.reply_to_message and message.reply_to_message.reply_markup: 39 | try: 40 | rm = message.reply_to_message.reply_markup 41 | btn = rm.inline_keyboard 42 | msg = get_file_id(message.reply_to_message) 43 | if msg: 44 | fileid = msg.file_id 45 | reply_text = message.reply_to_message.caption.html 46 | else: 47 | reply_text = message.reply_to_message.text.html 48 | fileid = None 49 | alert = None 50 | except: 51 | reply_text = "" 52 | btn = "[]" 53 | fileid = None 54 | alert = None 55 | 56 | elif message.reply_to_message and message.reply_to_message.media: 57 | try: 58 | msg = get_file_id(message.reply_to_message) 59 | fileid = msg.file_id if msg else None 60 | reply_text, btn, alert = gfilterparser(extracted[1], text) if message.reply_to_message.sticker else gfilterparser(message.reply_to_message.caption.html, text) 61 | except: 62 | reply_text = "" 63 | btn = "[]" 64 | alert = None 65 | elif message.reply_to_message and message.reply_to_message.text: 66 | try: 67 | fileid = None 68 | reply_text, btn, alert = gfilterparser(message.reply_to_message.text.html, text) 69 | except: 70 | reply_text = "" 71 | btn = "[]" 72 | alert = None 73 | else: 74 | return 75 | 76 | await add_gfilter('gfilters', text, reply_text, btn, fileid, alert) 77 | 78 | await message.reply_text( 79 | f"GFilter for `{text}` added", 80 | quote=True, 81 | parse_mode=enums.ParseMode.MARKDOWN 82 | ) 83 | 84 | 85 | @Client.on_message(filters.command(['viewgfilters', 'gfilters']) & filters.incoming & filters.user(ADMINS)) 86 | async def get_all_gfilters(client, message): 87 | texts = await get_gfilters('gfilters') 88 | count = await count_gfilters('gfilters') 89 | if count: 90 | gfilterlist = f"Total number of gfilters : {count}\n\n" 91 | 92 | for text in texts: 93 | keywords = " × `{}`\n".format(text) 94 | 95 | gfilterlist += keywords 96 | 97 | if len(gfilterlist) > 4096: 98 | with io.BytesIO(str.encode(gfilterlist.replace("`", ""))) as keyword_file: 99 | keyword_file.name = "keywords.txt" 100 | await message.reply_document( 101 | document=keyword_file, 102 | quote=True 103 | ) 104 | return 105 | else: 106 | gfilterlist = f"There are no active gfilters." 107 | 108 | await message.reply_text( 109 | text=gfilterlist, 110 | quote=True, 111 | parse_mode=enums.ParseMode.MARKDOWN 112 | ) 113 | 114 | @Client.on_message(filters.command('delg') & filters.incoming & filters.user(ADMINS)) 115 | async def deletegfilter(client, message): 116 | try: 117 | cmd, text = message.text.split(" ", 1) 118 | except: 119 | await message.reply_text( 120 | "Mention the gfiltername which you wanna delete!\n\n" 121 | "/delg gfiltername\n\n" 122 | "Use /viewgfilters to view all available gfilters", 123 | quote=True 124 | ) 125 | return 126 | 127 | query = text.lower() 128 | 129 | await delete_gfilter(message, query, 'gfilters') 130 | 131 | @Client.on_message(filters.command('delallg') & filters.user(ADMINS)) 132 | async def delallgfilters(client, message): 133 | await message.reply_text( 134 | f"Do you want to continue??", 135 | reply_markup=InlineKeyboardMarkup([ 136 | [InlineKeyboardButton(text="YES",callback_data="gfiltersdeleteallconfirm")], 137 | [InlineKeyboardButton(text="CANCEL",callback_data="gfiltersdeleteallcancel")] 138 | ]), 139 | quote=True 140 | ) -------------------------------------------------------------------------------- /plugins/genlink.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pyrogram import filters, Client, enums 3 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, UsernameInvalid, UsernameNotModified 4 | from info import ADMINS, LOG_CHANNEL, FILE_STORE_CHANNEL, PUBLIC_FILE_STORE 5 | from database.ia_filterdb import unpack_new_file_id 6 | from utils import temp 7 | import re 8 | import os 9 | import json 10 | import base64 11 | import logging 12 | 13 | logger = logging.getLogger(__name__) 14 | logger.setLevel(logging.INFO) 15 | 16 | async def allowed(_, __, message): 17 | if PUBLIC_FILE_STORE: 18 | return True 19 | if message.from_user and message.from_user.id in ADMINS: 20 | return True 21 | return False 22 | 23 | @Client.on_message(filters.command(['link', 'plink']) & filters.create(allowed)) 24 | async def gen_link_s(bot, message): 25 | replied = message.reply_to_message 26 | if not replied: 27 | return await message.reply('Reply to a message to get a shareable link.') 28 | file_type = replied.media 29 | if file_type not in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.AUDIO, enums.MessageMediaType.DOCUMENT]: 30 | return await message.reply("Reply to a supported media") 31 | if message.has_protected_content and message.chat.id not in ADMINS: 32 | return await message.reply("okDa") 33 | file_id, ref = unpack_new_file_id((getattr(replied, file_type.value)).file_id) 34 | string = 'filep_' if message.text.lower().strip() == "/plink" else 'file_' 35 | string += file_id 36 | outstr = base64.urlsafe_b64encode(string.encode("ascii")).decode().strip("=") 37 | await message.reply(f"Here is your Link:\nhttps://t.me/{temp.U_NAME}?start={outstr}") 38 | 39 | 40 | @Client.on_message(filters.command(['batch', 'pbatch']) & filters.create(allowed)) 41 | async def gen_link_batch(bot, message): 42 | if " " not in message.text: 43 | return await message.reply("Use correct format.\nExample /batch https://t.me/piroxbots/10 https://t.me/piroxbots/20.") 44 | links = message.text.strip().split(" ") 45 | if len(links) != 3: 46 | return await message.reply("Use correct format.\nExample /batch https://t.me/piroxbots/10 https://t.me/piroxbots/20.") 47 | cmd, first, last = links 48 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$") 49 | match = regex.match(first) 50 | if not match: 51 | return await message.reply('Invalid link') 52 | f_chat_id = match.group(4) 53 | f_msg_id = int(match.group(5)) 54 | if f_chat_id.isnumeric(): 55 | f_chat_id = int(("-100" + f_chat_id)) 56 | 57 | match = regex.match(last) 58 | if not match: 59 | return await message.reply('Invalid link') 60 | l_chat_id = match.group(4) 61 | l_msg_id = int(match.group(5)) 62 | if l_chat_id.isnumeric(): 63 | l_chat_id = int(("-100" + l_chat_id)) 64 | 65 | if f_chat_id != l_chat_id: 66 | return await message.reply("Chat ids not matched.") 67 | try: 68 | chat_id = (await bot.get_chat(f_chat_id)).id 69 | except ChannelInvalid: 70 | return await message.reply('This may be a private channel / group. Make me an admin over there to index the files.') 71 | except (UsernameInvalid, UsernameNotModified): 72 | return await message.reply('Invalid Link specified.') 73 | except Exception as e: 74 | return await message.reply(f'Errors - {e}') 75 | 76 | sts = await message.reply("Generating link for your message.\nThis may take time depending upon number of messages") 77 | if chat_id in FILE_STORE_CHANNEL: 78 | string = f"{f_msg_id}_{l_msg_id}_{chat_id}_{cmd.lower().strip()}" 79 | b_64 = base64.urlsafe_b64encode(string.encode("ascii")).decode().strip("=") 80 | return await sts.edit(f"Here is your link https://t.me/{temp.U_NAME}?start=DSTORE-{b_64}") 81 | 82 | FRMT = "Generating Link...\nTotal Messages: `{total}`\nDone: `{current}`\nRemaining: `{rem}`\nStatus: `{sts}`" 83 | 84 | outlist = [] 85 | 86 | # file store without db channel 87 | og_msg = 0 88 | tot = 0 89 | async for msg in bot.iter_messages(f_chat_id, l_msg_id, f_msg_id): 90 | tot += 1 91 | if msg.empty or msg.service: 92 | continue 93 | if not msg.media: 94 | # only media messages supported. 95 | continue 96 | try: 97 | file_type = msg.media 98 | file = getattr(msg, file_type.value) 99 | caption = getattr(msg, 'caption', '') 100 | if caption: 101 | caption = caption.html 102 | if file: 103 | file = { 104 | "file_id": file.file_id, 105 | "caption": caption, 106 | "title": getattr(file, "file_name", ""), 107 | "size": file.file_size, 108 | "protect": cmd.lower().strip() == "/pbatch", 109 | } 110 | 111 | og_msg +=1 112 | outlist.append(file) 113 | except: 114 | pass 115 | if not og_msg % 20: 116 | try: 117 | await sts.edit(FRMT.format(total=l_msg_id-f_msg_id, current=tot, rem=((l_msg_id-f_msg_id) - tot), sts="Saving Messages")) 118 | except: 119 | pass 120 | with open(f"batchmode_{message.from_user.id}.json", "w+") as out: 121 | json.dump(outlist, out) 122 | post = await bot.send_document(LOG_CHANNEL, f"batchmode_{message.from_user.id}.json", file_name="Batch.json", caption="⚠️Generated for filestore.") 123 | os.remove(f"batchmode_{message.from_user.id}.json") 124 | file_id, ref = unpack_new_file_id(post.document.file_id) 125 | await sts.edit(f"Here is your link\nContains `{og_msg}` files.\n https://t.me/{temp.U_NAME}?start=BATCH-{file_id}") 126 | -------------------------------------------------------------------------------- /info.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import environ 3 | import asyncio 4 | import json 5 | from collections import defaultdict 6 | from typing import Dict, List, Union 7 | from pyrogram import Client 8 | from time import time 9 | 10 | id_pattern = re.compile(r'^.\d+$') 11 | def is_enabled(value, default): 12 | if value.strip().lower() in ["on", "true", "yes", "1", "enable", "y"]: 13 | return True 14 | elif value.strip().lower() in ["off", "false", "no", "0", "disable", "n"]: 15 | return False 16 | else: 17 | return default 18 | 19 | # Bot information 20 | SESSION = environ.get('SESSION', 'Media_search') 21 | API_ID = int(environ.get('API_ID', '')) 22 | API_HASH = environ.get('API_HASH', '') 23 | BOT_TOKEN = environ.get('BOT_TOKEN', '') 24 | PORT = environ.get("PORT", "8080") 25 | 26 | # Bot settings 27 | CACHE_TIME = int(environ.get('CACHE_TIME', 300)) 28 | USE_CAPTION_FILTER = bool(environ.get('USE_CAPTION_FILTER', True)) 29 | BOT_START_TIME = time() 30 | 31 | # Bot images & videos 32 | PICS = (environ.get('PICS', 'https://telegra.ph/file/5553dc39f968b364d4856.jpg')).split() 33 | REQ_PICS = (environ.get('REQ_PICS', 'https://graph.org/file/5cb80fa6096997b7226b3.jpg')).split() 34 | NOR_IMG = environ.get("NOR_IMG", "https://telegra.ph/file/0593a3103ba1b9a5855bf.jpg") 35 | MELCOW_VID = environ.get("MELCOW_VID", "https://graph.org/file/72dff2b65352ba85d0a34.mp4") 36 | SPELL_IMG = environ.get("SPELL_IMG", "https://telegra.ph/file/2a888a370f479f4338f7c.jpg") 37 | 38 | # Admins, Channels & Users 39 | ADMINS = [int(admin) if id_pattern.search(admin) else admin for admin in environ.get('ADMINS', '').split()] 40 | CHANNELS = [int(ch) if id_pattern.search(ch) else ch for ch in environ.get('CHANNELS', '0').split()] 41 | auth_users = [int(user) if id_pattern.search(user) else user for user in environ.get('AUTH_USERS', '').split()] 42 | AUTH_USERS = (auth_users + ADMINS) if auth_users else [] 43 | auth_channel = environ.get('AUTH_CHANNEL') 44 | auth_grp = environ.get('AUTH_GROUP') 45 | AUTH_CHANNEL = int(auth_channel) if auth_channel and id_pattern.search(auth_channel) else None 46 | AUTH_GROUPS = [int(ch) for ch in auth_grp.split()] if auth_grp else None 47 | support_chat_id = environ.get('SUPPORT_CHAT_ID') 48 | reqst_channel = environ.get('REQST_CHANNEL_ID') 49 | REQST_CHANNEL = int(reqst_channel) if reqst_channel and id_pattern.search(reqst_channel) else None 50 | SUPPORT_CHAT_ID = -1001792675255 51 | NO_RESULTS_MSG = bool(environ.get("NO_RESULTS_MSG", False)) 52 | 53 | # MongoDB information 54 | DATABASE_URI = environ.get('DATABASE_URI', "") 55 | DATABASE_NAME = environ.get('DATABASE_NAME', "PIRO") 56 | COLLECTION_NAME = environ.get('COLLECTION_NAME', 'FILES') 57 | 58 | # Others 59 | DELETE_CHANNELS = [int(dch) if id_pattern.search(dch) else dch for dch in environ.get('DELETE_CHANNELS', '0').split()] 60 | MAX_B_TN = environ.get("MAX_B_TN", "10") 61 | MAX_BTN = is_enabled((environ.get('MAX_BTN', "True")), True) 62 | LOG_CHANNEL = int(environ.get('LOG_CHANNEL', 0)) 63 | SUPPORT_CHAT = environ.get('SUPPORT_CHAT', 'raixchat') 64 | P_TTI_SHOW_OFF = is_enabled((environ.get('P_TTI_SHOW_OFF', "True")), False) 65 | IMDB = is_enabled((environ.get('IMDB', "False")), True) 66 | AUTO_FFILTER = is_enabled((environ.get('AUTO_FFILTER', "True")), True) 67 | AUTO_DELETE = is_enabled((environ.get('AUTO_DELETE', "True")), True) 68 | SINGLE_BUTTON = is_enabled((environ.get('SINGLE_BUTTON', "True")), True) 69 | CUSTOM_FILE_CAPTION = environ.get("CUSTOM_FILE_CAPTION", '📂 File Name: {file_name} \n\n❤️‍🔥 Join [𝗕𝗟𝗔𝗦𝗧𝗘𝗥 𝗟𝗜𝗡𝗞𝗭](https://t.me/blaster_linkz)') 70 | BATCH_FILE_CAPTION = environ.get("BATCH_FILE_CAPTION", '') 71 | IMDB_TEMPLATE = environ.get("IMDB_TEMPLATE", '🏷 𝖳𝗂𝗍𝗅𝖾: {title} \n🔮 𝖸𝖾𝖺𝗋: {year} \n⭐️ 𝖱𝖺𝗍𝗂𝗇𝗀𝗌: {rating}/ 10 \n🎭 𝖦𝖾𝗇𝖾𝗋𝗌: {genres} \n\n🎊 𝖯𝗈𝗐𝖾𝗋𝖾𝖽 𝖡𝗒 [[𝖯𝖨𝖱𝖮]](t.me/piroxbots)') 72 | LONG_IMDB_DESCRIPTION = is_enabled(environ.get("LONG_IMDB_DESCRIPTION", "False"), False) 73 | SPELL_CHECK_REPLY = is_enabled(environ.get("SPELL_CHECK_REPLY", "True"), True) 74 | MAX_LIST_ELM = environ.get("MAX_LIST_ELM", None) 75 | INDEX_REQ_CHANNEL = int(environ.get('INDEX_REQ_CHANNEL', LOG_CHANNEL)) 76 | FILE_STORE_CHANNEL = [int(ch) for ch in (environ.get('FILE_STORE_CHANNEL', '')).split()] 77 | MELCOW_NEW_USERS = is_enabled((environ.get('MELCOW_NEW_USERS', "True")), True) 78 | PROTECT_CONTENT = is_enabled((environ.get('PROTECT_CONTENT', "False")), False) 79 | PUBLIC_FILE_STORE = is_enabled((environ.get('PUBLIC_FILE_STORE', "False")), True) 80 | 81 | LOG_STR = "Current Cusomized Configurations are:-\n" 82 | LOG_STR += ("IMDB Results are enabled, Bot will be showing imdb details for you queries.\n" if IMDB else "IMBD Results are disabled.\n") 83 | LOG_STR += ("P_TTI_SHOW_OFF found , Users will be redirected to send /start to Bot PM instead of sending file file directly\n" if P_TTI_SHOW_OFF else "P_TTI_SHOW_OFF is disabled files will be send in PM, instead of sending start.\n") 84 | LOG_STR += ("SINGLE_BUTTON is Found, filename and files size will be shown in a single button instead of two separate buttons\n" if SINGLE_BUTTON else "SINGLE_BUTTON is disabled , filename and file_sixe will be shown as different buttons\n") 85 | LOG_STR += (f"CUSTOM_FILE_CAPTION enabled with value {CUSTOM_FILE_CAPTION}, your files will be send along with this customized caption.\n" if CUSTOM_FILE_CAPTION else "No CUSTOM_FILE_CAPTION Found, Default captions of file will be used.\n") 86 | LOG_STR += ("Long IMDB storyline enabled." if LONG_IMDB_DESCRIPTION else "LONG_IMDB_DESCRIPTION is disabled , Plot will be shorter.\n") 87 | LOG_STR += ("Spell Check Mode Is Enabled, bot will be suggesting related movies if movie not found\n" if SPELL_CHECK_REPLY else "SPELL_CHECK_REPLY Mode disabled\n") 88 | LOG_STR += (f"MAX_LIST_ELM Found, long list will be shortened to first {MAX_LIST_ELM} elements\n" if MAX_LIST_ELM else "Full List of casts and crew will be shown in imdb template, restrict them by adding a value to MAX_LIST_ELM\n") 89 | LOG_STR += f"Your current IMDB template is {IMDB_TEMPLATE}" 90 | -------------------------------------------------------------------------------- /plugins/connection.py: -------------------------------------------------------------------------------- 1 | from pyrogram import filters, Client, enums 2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 3 | from database.connections_mdb import add_connection, all_connections, if_active, delete_connection 4 | from info import ADMINS 5 | from utils import temp 6 | import logging 7 | 8 | logger = logging.getLogger(__name__) 9 | logger.setLevel(logging.ERROR) 10 | 11 | 12 | @Client.on_message((filters.private | filters.group) & filters.command('connect')) 13 | async def addconnection(client, message): 14 | userid = message.from_user.id if message.from_user else None 15 | if not userid: 16 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 17 | chat_type = message.chat.type 18 | 19 | if chat_type == enums.ChatType.PRIVATE: 20 | try: 21 | cmd, group_id = message.text.split(" ", 1) 22 | except: 23 | await message.reply_text( 24 | "Enter in correct format!\n\n" 25 | "/connect groupid\n\n" 26 | "Get your Group id by adding this bot to your group and use /id", 27 | quote=True 28 | ) 29 | return 30 | 31 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 32 | group_id = message.chat.id 33 | 34 | try: 35 | st = await client.get_chat_member(group_id, userid) 36 | if ( 37 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 38 | and st.status != enums.ChatMemberStatus.OWNER 39 | and userid not in ADMINS 40 | ): 41 | await message.reply_text("You should be an admin in Given group!", quote=True) 42 | return 43 | except Exception as e: 44 | logger.exception(e) 45 | await message.reply_text( 46 | "Invalid Group ID!\n\nIf correct, Make sure I'm present in your group!!", 47 | quote=True, 48 | ) 49 | 50 | return 51 | try: 52 | st = await client.get_chat_member(group_id, "me") 53 | if st.status == enums.ChatMemberStatus.ADMINISTRATOR: 54 | ttl = await client.get_chat(group_id) 55 | title = ttl.title 56 | 57 | addcon = await add_connection(str(group_id), str(userid)) 58 | if addcon: 59 | await message.reply_text( 60 | f"Successfully connected to **{title}**\nNow manage your group from my pm !", 61 | quote=True, 62 | parse_mode=enums.ParseMode.MARKDOWN 63 | ) 64 | if chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 65 | await client.send_message( 66 | userid, 67 | f"Connected to **{title}** !", 68 | parse_mode=enums.ParseMode.MARKDOWN 69 | ) 70 | else: 71 | await message.reply_text( 72 | "You're already connected to this chat!", 73 | quote=True 74 | ) 75 | else: 76 | await message.reply_text("Add me as an admin in group", quote=True) 77 | except Exception as e: 78 | logger.exception(e) 79 | await message.reply_text('Some error occurred! Try again later.', quote=True) 80 | return 81 | 82 | 83 | @Client.on_message((filters.private | filters.group) & filters.command('disconnect')) 84 | async def deleteconnection(client, message): 85 | userid = message.from_user.id if message.from_user else None 86 | if not userid: 87 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 88 | chat_type = message.chat.type 89 | 90 | if chat_type == enums.ChatType.PRIVATE: 91 | await message.reply_text("Run /connections to view or disconnect from groups!", quote=True) 92 | 93 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 94 | group_id = message.chat.id 95 | 96 | st = await client.get_chat_member(group_id, userid) 97 | if ( 98 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 99 | and st.status != enums.ChatMemberStatus.OWNER 100 | and str(userid) not in ADMINS 101 | ): 102 | return 103 | 104 | delcon = await delete_connection(str(userid), str(group_id)) 105 | if delcon: 106 | await message.reply_text("Successfully disconnected from this chat", quote=True) 107 | else: 108 | await message.reply_text("This chat isn't connected to me!\nDo /connect to connect.", quote=True) 109 | 110 | 111 | @Client.on_message(filters.private & filters.command(["connections"])) 112 | async def connections(client, message): 113 | userid = message.from_user.id 114 | 115 | groupids = await all_connections(str(userid)) 116 | if groupids is None: 117 | await message.reply_text( 118 | "There are no active connections!! Connect to some groups first.", 119 | quote=True 120 | ) 121 | return 122 | buttons = [] 123 | for groupid in groupids: 124 | try: 125 | ttl = await client.get_chat(int(groupid)) 126 | title = ttl.title 127 | active = await if_active(str(userid), str(groupid)) 128 | act = " - ACTIVE" if active else "" 129 | buttons.append( 130 | [ 131 | InlineKeyboardButton( 132 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}" 133 | ) 134 | ] 135 | ) 136 | except: 137 | pass 138 | if buttons: 139 | await message.reply_text( 140 | "Your connected group details ;\n\n", 141 | reply_markup=InlineKeyboardMarkup(buttons), 142 | quote=True 143 | ) 144 | else: 145 | await message.reply_text( 146 | "There are no active connections!! Connect to some groups first.", 147 | quote=True 148 | ) 149 | -------------------------------------------------------------------------------- /database/ia_filterdb.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from struct import pack 3 | import re 4 | import base64 5 | from pyrogram.file_id import FileId 6 | from pymongo.errors import DuplicateKeyError 7 | from umongo import Instance, Document, fields 8 | from motor.motor_asyncio import AsyncIOMotorClient 9 | from marshmallow.exceptions import ValidationError 10 | from info import DATABASE_URI, DATABASE_NAME, COLLECTION_NAME, USE_CAPTION_FILTER, MAX_B_TN 11 | from utils import get_settings, save_group_settings 12 | 13 | logger = logging.getLogger(__name__) 14 | logger.setLevel(logging.INFO) 15 | 16 | 17 | client = AsyncIOMotorClient(DATABASE_URI) 18 | db = client[DATABASE_NAME] 19 | instance = Instance.from_db(db) 20 | 21 | @instance.register 22 | class Media(Document): 23 | file_id = fields.StrField(attribute='_id') 24 | file_ref = fields.StrField(allow_none=True) 25 | file_name = fields.StrField(required=True) 26 | file_size = fields.IntField(required=True) 27 | file_type = fields.StrField(allow_none=True) 28 | mime_type = fields.StrField(allow_none=True) 29 | caption = fields.StrField(allow_none=True) 30 | 31 | class Meta: 32 | indexes = ('$file_name', ) 33 | collection_name = COLLECTION_NAME 34 | 35 | 36 | async def save_file(media): 37 | """Save file in database""" 38 | 39 | # TODO: Find better way to get same file_id for same media to avoid duplicates 40 | file_id, file_ref = unpack_new_file_id(media.file_id) 41 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 42 | try: 43 | file = Media( 44 | file_id=file_id, 45 | file_ref=file_ref, 46 | file_name=file_name, 47 | file_size=media.file_size, 48 | file_type=media.file_type, 49 | mime_type=media.mime_type, 50 | caption=media.caption.html if media.caption else None, 51 | ) 52 | except ValidationError: 53 | logger.exception('Error occurred while saving file in database') 54 | return False, 2 55 | else: 56 | try: 57 | await file.commit() 58 | except DuplicateKeyError: 59 | logger.warning( 60 | f'{getattr(media, "file_size", "NO_FILE")} is already saved in database' 61 | ) 62 | 63 | return False, 0 64 | else: 65 | logger.info(f'{getattr(media, "file_size", "NO_FILE")} is saved to database') 66 | return True, 1 67 | 68 | 69 | 70 | async def get_search_results(chat_id, query, file_type=None, max_results=10, offset=0, filter=False): 71 | """For given query return (results, next_offset)""" 72 | if chat_id is not None: 73 | settings = await get_settings(int(chat_id)) 74 | try: 75 | if settings['max_btn']: 76 | max_results = 10 77 | else: 78 | max_results = int(MAX_B_TN) 79 | except KeyError: 80 | await save_group_settings(int(chat_id), 'max_btn', False) 81 | settings = await get_settings(int(chat_id)) 82 | if settings['max_btn']: 83 | max_results = 10 84 | else: 85 | max_results = int(MAX_B_TN) 86 | query = query.strip() 87 | #if filter: 88 | #better ? 89 | #query = query.replace(' ', r'(\s|\.|\+|\-|_)') 90 | #raw_pattern = r'(\s|_|\-|\.|\+)' + query + r'(\s|_|\-|\.|\+)' 91 | if not query: 92 | raw_pattern = '.' 93 | elif ' ' not in query: 94 | raw_pattern = r'(\b|[\.\+\-_])' + query + r'(\b|[\.\+\-_])' 95 | else: 96 | raw_pattern = query.replace(' ', r'.*[\s\.\+\-_]') 97 | 98 | try: 99 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 100 | except: 101 | return [] 102 | 103 | if USE_CAPTION_FILTER: 104 | filter = {'$or': [{'file_name': regex}, {'caption': regex}]} 105 | else: 106 | filter = {'file_name': regex} 107 | 108 | if file_type: 109 | filter['file_type'] = file_type 110 | 111 | total_results = await Media.count_documents(filter) 112 | next_offset = offset + max_results 113 | 114 | if next_offset > total_results: 115 | next_offset = '' 116 | 117 | cursor = Media.find(filter) 118 | # Sort by recent 119 | cursor.sort('$natural', -1) 120 | # Slice files according to offset and max results 121 | cursor.skip(offset).limit(max_results) 122 | # Get list of files 123 | files = await cursor.to_list(length=max_results) 124 | 125 | return files, next_offset, total_results 126 | 127 | async def get_bad_files(query, file_type=None, filter=False): 128 | """For given query return (results, next_offset)""" 129 | query = query.strip() 130 | #if filter: 131 | #better ? 132 | #query = query.replace(' ', r'(\s|\.|\+|\-|_)') 133 | #raw_pattern = r'(\s|_|\-|\.|\+)' + query + r'(\s|_|\-|\.|\+)' 134 | if not query: 135 | raw_pattern = '.' 136 | elif ' ' not in query: 137 | raw_pattern = r'(\b|[\.\+\-_])' + query + r'(\b|[\.\+\-_])' 138 | else: 139 | raw_pattern = query.replace(' ', r'.*[\s\.\+\-_]') 140 | 141 | try: 142 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 143 | except: 144 | return [] 145 | 146 | if USE_CAPTION_FILTER: 147 | filter = {'$or': [{'file_name': regex}, {'caption': regex}]} 148 | else: 149 | filter = {'file_name': regex} 150 | 151 | if file_type: 152 | filter['file_type'] = file_type 153 | 154 | total_results = await Media.count_documents(filter) 155 | 156 | cursor = Media.find(filter) 157 | # Sort by recent 158 | cursor.sort('$natural', -1) 159 | # Get list of files 160 | files = await cursor.to_list(length=total_results) 161 | 162 | return files, total_results 163 | 164 | async def get_file_details(query): 165 | filter = {'file_id': query} 166 | cursor = Media.find(filter) 167 | filedetails = await cursor.to_list(length=1) 168 | return filedetails 169 | 170 | 171 | def encode_file_id(s: bytes) -> str: 172 | r = b"" 173 | n = 0 174 | 175 | for i in s + bytes([22]) + bytes([4]): 176 | if i == 0: 177 | n += 1 178 | else: 179 | if n: 180 | r += b"\x00" + bytes([n]) 181 | n = 0 182 | 183 | r += bytes([i]) 184 | 185 | return base64.urlsafe_b64encode(r).decode().rstrip("=") 186 | 187 | 188 | def encode_file_ref(file_ref: bytes) -> str: 189 | return base64.urlsafe_b64encode(file_ref).decode().rstrip("=") 190 | 191 | 192 | def unpack_new_file_id(new_file_id): 193 | """Return file_id, file_ref""" 194 | decoded = FileId.decode(new_file_id) 195 | file_id = encode_file_id( 196 | pack( 197 | " 2 | 3 |

4 |

5 | PiroAutoFilterBot 6 |

7 | 8 | ![Typing SVG](https://readme-typing-svg.herokuapp.com/?lines=PIRO+MOVIE+SEARCH+BOT+!;CREATED+BY+PIRO!;A+ADVANCE+BOT+WITH+COOL+FEATURES!)

9 | Stars 10 | 11 | License 12 | Python 13 | 14 | 15 | 16 | 17 | ### Features 18 | 19 | - [x] Indexes Files above 2GB 20 | - [x] Force Subscription 21 | - [x] Automatic File Filtering 22 | - [x] Double Filter Button 23 | - [x] Single Filter Button 24 | - [x] Forward Restriction 25 | - [x] File Protect 26 | - [x] Manual File Filtering 27 | - [x] Global File Filtering 28 | - [x] IMDB 29 | - [x] Admin Commands 30 | - [x] User Broadcast 31 | - [x] Group Broadcast 32 | - [x] Index 33 | - [x] IMDB search 34 | - [x] Inline Search 35 | - [x] Random pics 36 | - [x] ids and User info 37 | - [x] Stats 38 | - [x] Users 39 | - [x] Chats 40 | - [x] User Ban 41 | - [x] User Unban 42 | - [x] Chat Leave 43 | - [x] Chat Disable 44 | - [x] Channel 45 | - [x] Spelling Check Feature 46 | - [x] File Store 47 | - [x] Auto Delete 48 | - [x] And More.... 49 | 50 | 51 | ### Required Variables 52 | * `BOT_TOKEN`: Create a bot using [@BotFather](https://telegram.dog/BotFather), and get the Telegram API token. 53 | * `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) 54 | * `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) 55 | * `CHANNELS`: Username or ID of channel or group. Separate multiple IDs by space 56 | * `ADMINS`: Username or ID of Admin. Separate multiple Admins by space 57 | * `DATABASE_URI`: [mongoDB](https://www.mongodb.com) URI. Get this value from [mongoDB](https://www.mongodb.com). For more help watch this [video](https://youtu.be/1G1XwEOnxxo) 58 | * `DATABASE_NAME`: Name of the database in [mongoDB](https://www.mongodb.com). For more help watch this [video](https://youtu.be/1G1XwEOnxxo) 59 | * `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. 60 | ### Optional Variables 61 | * `PICS`: Telegraph links of images to show in start message.( Multiple images can be used separated by space ) 62 | * `FILE_STORE_CHANNEL`: Channel from were file store links of posts should be made.Separate multiple IDs by space 63 | * Check [info.py](https://github.com/ritheshrkrm/PiroAutoFilterBot/blob/master/info.py) for more 64 | 65 | ### Deployment Methods 66 |
Deploy To Heroku 67 |

68 |
69 | 70 | Deploy To Heroku 71 | 72 |

73 |
74 | 75 |
Deploy To Koyeb 76 | The fastest way to deploy the application is to click the Deploy to Koyeb button below. 77 | 78 | [![Deploy to Koyeb](https://www.koyeb.com/static/images/deploy/button.svg)](https://app.koyeb.com/deploy?type=git&repository=https://github.com/ritheshrkrm/PiroAutoFilterBot&branch=main&name=pirobot) 79 |
80 | 81 |
Deploy on Railway 82 | 83 | Deploy on Railway 84 | 85 |
86 | 87 |
Deploy To Render 88 |
89 | 90 | Deploy to Render 91 | 92 |
93 | 94 |
Deploy To VPS 95 |

96 |

 97 | Use VPS Branch
 98 | git clone https://github.com/ritheshrkrm/PiroAutoFilterBot
 99 | # Install Packages
100 | pip3 install -U -r requirements.txt
101 | Edit info.py with variables as given below then run bot
102 | python3 bot.py
103 | 
104 |

105 |
106 | 107 | 108 | ### Commands 109 | ``` 110 | alive - check bot alive 111 | ping - pong 112 | gfilter - to add a global filter 113 | delg - to delete a global filter 114 | broadcast - to broadcast a message to all users 115 | group_broadcast - to broadcast a message to all groups 116 | settings - get settings 117 | logs - to get the rescent errors 118 | stats - to get status of files in db 119 | filter - add manual filters 120 | filters - view filters 121 | connect - connect to PM 122 | disconnect - disconnect from PM 123 | del - delete a filter 124 | delall - delete all filters 125 | id - get tg ids 126 | imdb - fetch info from imdb 127 | users - to get list of my users and ids 128 | chats - to get list of the my chats and ids 129 | leave - to leave from a chat 130 | disable - do disable a chat 131 | enable - re-enable chat 132 | ban - to ban a user 133 | unban - to unban a use 134 | ``` 135 | 136 | 137 | 138 | ### Thanks to 139 | - Thanks To EvaMaria Devs For Their AutoFIlterBot 140 | - Thanks To Me For Wasting Time On This Repo Instead Of Studying :) 141 | 142 | ### Note 🏷️ 143 | - Importing this repo instead of forking is strictly prohibited 🚫 Kindly fork and edit as your wish (Must Give Credits for devs) 🙃 144 | - If you find any bugs or errors, report it to the developer. 145 | * [![Contact Developer](https://img.shields.io/static/v1?label=Contact+Developer&message=On+Telegram&color=critical)](https://telegram.me/raixchat) 146 | 147 | ### TELAGRAM SUPPORT 148 | 149 | * [![PIRO BOTZ](https://img.shields.io/static/v1?label=PIRO&message=BOTZ&color=critical)](https://telegram.me/piroxbots) 150 | 151 | 152 | 153 | ### Disclaimer 154 | [![GNU Affero General Public License 2.0](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.en.html#header) 155 | Licensed under [GNU AGPL 2.0.](https://github.com/ritheshrkrm/PiroAutoFilterBot/blob/master/LICENSE) 156 | Selling The Codes To Other People For Money Is *Strictly Prohibited*. 157 | -------------------------------------------------------------------------------- /plugins/misc.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyrogram import Client, filters, enums 3 | from pyrogram.errors.exceptions.bad_request_400 import UserNotParticipant, MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty 4 | from info import IMDB_TEMPLATE 5 | from utils import extract_user, get_file_id, get_poster, last_online 6 | import time 7 | from datetime import datetime 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 9 | import logging 10 | logger = logging.getLogger(__name__) 11 | logger.setLevel(logging.ERROR) 12 | 13 | @Client.on_message(filters.command('id')) 14 | async def showid(client, message): 15 | chat_type = message.chat.type 16 | if chat_type == enums.ChatType.PRIVATE: 17 | user_id = message.chat.id 18 | first = message.from_user.first_name 19 | last = message.from_user.last_name or "" 20 | username = message.from_user.username 21 | dc_id = message.from_user.dc_id or "" 22 | await message.reply_text( 23 | f"➲ First Name: {first}\n➲ Last Name: {last}\n➲ Username: {username}\n➲ Telegram ID: {user_id}\n➲ Data Centre: {dc_id}", 24 | quote=True 25 | ) 26 | 27 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 28 | _id = "" 29 | _id += ( 30 | "➲ Chat ID: " 31 | f"{message.chat.id}\n" 32 | ) 33 | if message.reply_to_message: 34 | _id += ( 35 | "➲ User ID: " 36 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n" 37 | "➲ Replied User ID: " 38 | f"{message.reply_to_message.from_user.id if message.reply_to_message.from_user else 'Anonymous'}\n" 39 | ) 40 | file_info = get_file_id(message.reply_to_message) 41 | else: 42 | _id += ( 43 | "➲ User ID: " 44 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n" 45 | ) 46 | file_info = get_file_id(message) 47 | if file_info: 48 | _id += ( 49 | f"{file_info.message_type}: " 50 | f"{file_info.file_id}\n" 51 | ) 52 | await message.reply_text( 53 | _id, 54 | quote=True 55 | ) 56 | 57 | @Client.on_message(filters.command(["info"])) 58 | async def who_is(client, message): 59 | status_message = await message.reply_text( 60 | "`Fetching user info...`" 61 | ) 62 | await status_message.edit( 63 | "`Processing user info...`" 64 | ) 65 | from_user = None 66 | from_user_id, _ = extract_user(message) 67 | try: 68 | from_user = await client.get_users(from_user_id) 69 | except Exception as error: 70 | await status_message.edit(str(error)) 71 | return 72 | if from_user is None: 73 | return await status_message.edit("no valid user_id / message specified") 74 | message_out_str = "" 75 | message_out_str += f"➲First Name: {from_user.first_name}\n" 76 | last_name = from_user.last_name or "None" 77 | message_out_str += f"➲Last Name: {last_name}\n" 78 | message_out_str += f"➲Telegram ID: {from_user.id}\n" 79 | username = from_user.username or "None" 80 | dc_id = from_user.dc_id or "[User Doesn't Have A Valid DP]" 81 | message_out_str += f"➲Data Centre: {dc_id}\n" 82 | message_out_str += f"➲User Name: @{username}\n" 83 | message_out_str += f"➲User 𝖫𝗂𝗇𝗄: Click Here\n" 84 | if message.chat.type in ((enums.ChatType.SUPERGROUP, enums.ChatType.CHANNEL)): 85 | try: 86 | chat_member_p = await message.chat.get_member(from_user.id) 87 | joined_date = ( 88 | chat_member_p.joined_date or datetime.now() 89 | ).strftime("%Y.%m.%d %H:%M:%S") 90 | message_out_str += ( 91 | "➲Joined this Chat on: " 92 | f"{joined_date}" 93 | "\n" 94 | ) 95 | except UserNotParticipant: 96 | pass 97 | chat_photo = from_user.photo 98 | if chat_photo: 99 | local_user_photo = await client.download_media( 100 | message=chat_photo.big_file_id 101 | ) 102 | buttons = [[ 103 | InlineKeyboardButton('🔐 𝖢𝗅𝗈𝗌𝖾', callback_data='close_data') 104 | ]] 105 | reply_markup = InlineKeyboardMarkup(buttons) 106 | await message.reply_photo( 107 | photo=local_user_photo, 108 | quote=True, 109 | reply_markup=reply_markup, 110 | caption=message_out_str, 111 | parse_mode=enums.ParseMode.HTML, 112 | disable_notification=True 113 | ) 114 | os.remove(local_user_photo) 115 | else: 116 | buttons = [[ 117 | InlineKeyboardButton('🔐 𝖢𝗅𝗈𝗌𝖾', callback_data='close_data') 118 | ]] 119 | reply_markup = InlineKeyboardMarkup(buttons) 120 | await message.reply_text( 121 | text=message_out_str, 122 | reply_markup=reply_markup, 123 | quote=True, 124 | parse_mode=enums.ParseMode.HTML, 125 | disable_notification=True 126 | ) 127 | await status_message.delete() 128 | 129 | @Client.on_message(filters.command(["imdb", 'search'])) 130 | async def imdb_search(client, message): 131 | if ' ' in message.text: 132 | k = await message.reply('Searching IMDb....') 133 | r, title = message.text.split(None, 1) 134 | movies = await get_poster(title, bulk=True) 135 | if not movies: 136 | return await message.reply("No results Found") 137 | btn = [ 138 | [ 139 | InlineKeyboardButton( 140 | text=f"{movie.get('title')} - {movie.get('year')}", 141 | callback_data=f"imdb#{movie.movieID}", 142 | ) 143 | ] 144 | for movie in movies 145 | ] 146 | await k.edit('𝖧𝖾𝗋𝖾 𝗂𝗌 𝗐𝗁𝖺𝗍 𝗂 𝖿𝗈𝗎𝗇𝖽 𝗈𝗇 𝖨𝖬𝖣𝖻', reply_markup=InlineKeyboardMarkup(btn)) 147 | else: 148 | await message.reply('Give me a movie / series Name') 149 | 150 | @Client.on_callback_query(filters.regex('^imdb')) 151 | async def imdb_callback(bot: Client, quer_y: CallbackQuery): 152 | i, movie = quer_y.data.split('#') 153 | imdb = await get_poster(query=movie, id=True) 154 | btn = [ 155 | [ 156 | InlineKeyboardButton( 157 | text=f"{imdb.get('title')}", 158 | url=imdb['url'], 159 | ) 160 | ] 161 | ] 162 | message = quer_y.message.reply_to_message or quer_y.message 163 | if imdb: 164 | caption = IMDB_TEMPLATE.format( 165 | query = imdb['title'], 166 | title = imdb['title'], 167 | votes = imdb['votes'], 168 | aka = imdb["aka"], 169 | seasons = imdb["seasons"], 170 | box_office = imdb['box_office'], 171 | localized_title = imdb['localized_title'], 172 | kind = imdb['kind'], 173 | imdb_id = imdb["imdb_id"], 174 | cast = imdb["cast"], 175 | runtime = imdb["runtime"], 176 | countries = imdb["countries"], 177 | certificates = imdb["certificates"], 178 | languages = imdb["languages"], 179 | director = imdb["director"], 180 | writer = imdb["writer"], 181 | producer = imdb["producer"], 182 | composer = imdb["composer"], 183 | cinematographer = imdb["cinematographer"], 184 | music_team = imdb["music_team"], 185 | distributors = imdb["distributors"], 186 | release_date = imdb['release_date'], 187 | year = imdb['year'], 188 | genres = imdb['genres'], 189 | poster = imdb['poster'], 190 | plot = imdb['plot'], 191 | rating = imdb['rating'], 192 | url = imdb['url'], 193 | **locals() 194 | ) 195 | else: 196 | caption = "No Results" 197 | if imdb.get('poster'): 198 | try: 199 | await quer_y.message.reply_photo(photo=imdb['poster'], caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 200 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty): 201 | pic = imdb.get('poster') 202 | poster = pic.replace('.jpg', "._V1_UX360.jpg") 203 | await quer_y.message.reply_photo(photo=poster, caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 204 | except Exception as e: 205 | logger.exception(e) 206 | await quer_y.message.reply(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 207 | await quer_y.message.delete() 208 | else: 209 | await quer_y.message.edit(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 210 | await quer_y.answer() 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /plugins/index.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import asyncio 3 | from pyrogram import Client, filters, enums 4 | from pyrogram.errors import FloodWait 5 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, ChatAdminRequired, UsernameInvalid, UsernameNotModified 6 | from info import ADMINS 7 | from info import INDEX_REQ_CHANNEL as LOG_CHANNEL 8 | from database.ia_filterdb import save_file 9 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 10 | from utils import temp 11 | import re 12 | logger = logging.getLogger(__name__) 13 | logger.setLevel(logging.INFO) 14 | lock = asyncio.Lock() 15 | 16 | 17 | @Client.on_callback_query(filters.regex(r'^index')) 18 | async def index_files(bot, query): 19 | if query.data.startswith('index_cancel'): 20 | temp.CANCEL = True 21 | return await query.answer("Cancelling Indexing") 22 | _, raju, chat, lst_msg_id, from_user = query.data.split("#") 23 | if raju == 'reject': 24 | await query.message.delete() 25 | await bot.send_message(int(from_user), 26 | f'Your Submission for indexing {chat} has been decliened by our moderators.', 27 | reply_to_message_id=int(lst_msg_id)) 28 | return 29 | 30 | if lock.locked(): 31 | return await query.answer('Wait until previous process complete.', show_alert=True) 32 | msg = query.message 33 | 34 | await query.answer('Processing...⏳', show_alert=True) 35 | if int(from_user) not in ADMINS: 36 | await bot.send_message(int(from_user), 37 | f'Your Submission for indexing {chat} has been accepted by our moderators and will be added soon.', 38 | reply_to_message_id=int(lst_msg_id)) 39 | await msg.edit( 40 | "Starting Indexing", 41 | reply_markup=InlineKeyboardMarkup( 42 | [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 43 | ) 44 | ) 45 | try: 46 | chat = int(chat) 47 | except: 48 | chat = chat 49 | await index_files_to_db(int(lst_msg_id), chat, msg, bot) 50 | 51 | 52 | @Client.on_message((filters.forwarded | (filters.regex("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$")) & filters.text ) & filters.private & filters.incoming) 53 | async def send_for_index(bot, message): 54 | if message.text: 55 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$") 56 | match = regex.match(message.text) 57 | if not match: 58 | return await message.reply('Invalid link') 59 | chat_id = match.group(4) 60 | last_msg_id = int(match.group(5)) 61 | if chat_id.isnumeric(): 62 | chat_id = int(("-100" + chat_id)) 63 | elif message.forward_from_chat.type == enums.ChatType.CHANNEL: 64 | last_msg_id = message.forward_from_message_id 65 | chat_id = message.forward_from_chat.username or message.forward_from_chat.id 66 | else: 67 | return 68 | try: 69 | await bot.get_chat(chat_id) 70 | except ChannelInvalid: 71 | return await message.reply('This may be a private channel / group. Make me an admin over there to index the files.') 72 | except (UsernameInvalid, UsernameNotModified): 73 | return await message.reply('Invalid Link specified.') 74 | except Exception as e: 75 | logger.exception(e) 76 | return await message.reply(f'Errors - {e}') 77 | try: 78 | k = await bot.get_messages(chat_id, last_msg_id) 79 | except: 80 | return await message.reply('Make Sure That Iam An Admin In The Channel, if channel is private') 81 | if k.empty: 82 | return await message.reply('This may be group and iam not a admin of the group.') 83 | 84 | if message.from_user.id in ADMINS: 85 | buttons = [ 86 | [ 87 | InlineKeyboardButton('Yes', 88 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 89 | ], 90 | [ 91 | InlineKeyboardButton('close', callback_data='close_data'), 92 | ] 93 | ] 94 | reply_markup = InlineKeyboardMarkup(buttons) 95 | return await message.reply( 96 | f'Do you Want To Index This Channel/ Group ?\n\nChat ID/ Username: {chat_id}\nLast Message ID: {last_msg_id}', 97 | reply_markup=reply_markup) 98 | 99 | if type(chat_id) is int: 100 | try: 101 | link = (await bot.create_chat_invite_link(chat_id)).invite_link 102 | except ChatAdminRequired: 103 | return await message.reply('Make sure iam an admin in the chat and have permission to invite users.') 104 | else: 105 | link = f"@{message.forward_from_chat.username}" 106 | buttons = [ 107 | [ 108 | InlineKeyboardButton('Accept Index', 109 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 110 | ], 111 | [ 112 | InlineKeyboardButton('Reject Index', 113 | callback_data=f'index#reject#{chat_id}#{message.id}#{message.from_user.id}'), 114 | ] 115 | ] 116 | reply_markup = InlineKeyboardMarkup(buttons) 117 | await bot.send_message(LOG_CHANNEL, 118 | f'#IndexRequest\n\nBy : {message.from_user.mention} ({message.from_user.id})\nChat ID/ Username - {chat_id}\nLast Message ID - {last_msg_id}\nInviteLink - {link}', 119 | reply_markup=reply_markup) 120 | await message.reply('ThankYou For the Contribution, Wait For My Moderators to verify the files.') 121 | 122 | 123 | @Client.on_message(filters.command('setskip') & filters.user(ADMINS)) 124 | async def set_skip_number(bot, message): 125 | if ' ' in message.text: 126 | _, skip = message.text.split(" ") 127 | try: 128 | skip = int(skip) 129 | except: 130 | return await message.reply("Skip number should be an integer.") 131 | await message.reply(f"Successfully set SKIP number as {skip}") 132 | temp.CURRENT = int(skip) 133 | else: 134 | await message.reply("Give me a skip number") 135 | 136 | 137 | async def index_files_to_db(lst_msg_id, chat, msg, bot): 138 | total_files = 0 139 | duplicate = 0 140 | errors = 0 141 | deleted = 0 142 | no_media = 0 143 | unsupported = 0 144 | async with lock: 145 | try: 146 | current = temp.CURRENT 147 | temp.CANCEL = False 148 | async for message in bot.iter_messages(chat, lst_msg_id, temp.CURRENT): 149 | if temp.CANCEL: 150 | await msg.edit(f"Successfully Cancelled!!\n\nSaved {total_files} files to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}") 151 | break 152 | current += 1 153 | if current % 20 == 0: 154 | can = [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 155 | reply = InlineKeyboardMarkup(can) 156 | await asyncio.sleep(2) 157 | await msg.edit_text( 158 | text=f"Total messages fetched: {current}\nTotal messages saved: {total_files}\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}", 159 | reply_markup=reply) 160 | if message.empty: 161 | deleted += 1 162 | continue 163 | elif not message.media: 164 | no_media += 1 165 | continue 166 | elif message.media not in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.AUDIO, enums.MessageMediaType.DOCUMENT]: 167 | unsupported += 1 168 | continue 169 | media = getattr(message, message.media.value, None) 170 | if not media: 171 | unsupported += 1 172 | continue 173 | media.file_type = message.media.value 174 | media.caption = message.caption 175 | aynav, vnay = await save_file(media) 176 | if aynav: 177 | total_files += 1 178 | elif vnay == 0: 179 | duplicate += 1 180 | elif vnay == 2: 181 | errors += 1 182 | except Exception as e: 183 | logger.exception(e) 184 | await msg.edit(f'Error: {e}') 185 | else: 186 | await msg.edit(f'Succesfully saved {total_files} to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}') 187 | -------------------------------------------------------------------------------- /plugins/filters.py: -------------------------------------------------------------------------------- 1 | import io 2 | from pyrogram import filters, Client, enums 3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 4 | from database.filters_mdb import( 5 | add_filter, 6 | get_filters, 7 | delete_filter, 8 | count_filters 9 | ) 10 | 11 | from database.connections_mdb import active_connection 12 | from utils import get_file_id, parser, split_quotes 13 | from info import ADMINS 14 | 15 | 16 | @Client.on_message(filters.command(['filter', 'addf']) & filters.incoming) 17 | async def addfilter(client, message): 18 | userid = message.from_user.id if message.from_user else None 19 | if not userid: 20 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 21 | chat_type = message.chat.type 22 | args = message.text.html.split(None, 1) 23 | 24 | if chat_type == enums.ChatType.PRIVATE: 25 | grpid = await active_connection(str(userid)) 26 | if grpid is not None: 27 | grp_id = grpid 28 | try: 29 | chat = await client.get_chat(grpid) 30 | title = chat.title 31 | except: 32 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 33 | return 34 | else: 35 | await message.reply_text("I'm not connected to any groups!", quote=True) 36 | return 37 | 38 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 39 | grp_id = message.chat.id 40 | title = message.chat.title 41 | 42 | else: 43 | return 44 | 45 | st = await client.get_chat_member(grp_id, userid) 46 | if ( 47 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 48 | and st.status != enums.ChatMemberStatus.OWNER 49 | and str(userid) not in ADMINS 50 | ): 51 | return 52 | 53 | 54 | if len(args) < 2: 55 | await message.reply_text("Command Incomplete :(", quote=True) 56 | return 57 | 58 | extracted = split_quotes(args[1]) 59 | text = extracted[0].lower() 60 | 61 | if not message.reply_to_message and len(extracted) < 2: 62 | await message.reply_text("Add some content to save your filter!", quote=True) 63 | return 64 | 65 | if (len(extracted) >= 2) and not message.reply_to_message: 66 | reply_text, btn, alert = parser(extracted[1], text) 67 | fileid = None 68 | if not reply_text: 69 | await message.reply_text("You cannot have buttons alone, give some text to go with it!", quote=True) 70 | return 71 | 72 | elif message.reply_to_message and message.reply_to_message.reply_markup: 73 | try: 74 | rm = message.reply_to_message.reply_markup 75 | btn = rm.inline_keyboard 76 | msg = get_file_id(message.reply_to_message) 77 | if msg: 78 | fileid = msg.file_id 79 | reply_text = message.reply_to_message.caption.html 80 | else: 81 | reply_text = message.reply_to_message.text.html 82 | fileid = None 83 | alert = None 84 | except: 85 | reply_text = "" 86 | btn = "[]" 87 | fileid = None 88 | alert = None 89 | 90 | elif message.reply_to_message and message.reply_to_message.media: 91 | try: 92 | msg = get_file_id(message.reply_to_message) 93 | fileid = msg.file_id if msg else None 94 | reply_text, btn, alert = parser(extracted[1], text) if message.reply_to_message.sticker else parser(message.reply_to_message.caption.html, text) 95 | except: 96 | reply_text = "" 97 | btn = "[]" 98 | alert = None 99 | elif message.reply_to_message and message.reply_to_message.text: 100 | try: 101 | fileid = None 102 | reply_text, btn, alert = parser(message.reply_to_message.text.html, text) 103 | except: 104 | reply_text = "" 105 | btn = "[]" 106 | alert = None 107 | else: 108 | return 109 | 110 | await add_filter(grp_id, text, reply_text, btn, fileid, alert) 111 | 112 | await message.reply_text( 113 | f"Filter for `{text}` added in **{title}**", 114 | quote=True, 115 | parse_mode=enums.ParseMode.MARKDOWN 116 | ) 117 | 118 | 119 | @Client.on_message(filters.command(['viewfilters', 'filters']) & filters.incoming) 120 | async def get_all(client, message): 121 | 122 | chat_type = message.chat.type 123 | userid = message.from_user.id if message.from_user else None 124 | if not userid: 125 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 126 | if chat_type == enums.ChatType.PRIVATE: 127 | userid = message.from_user.id 128 | grpid = await active_connection(str(userid)) 129 | if grpid is not None: 130 | grp_id = grpid 131 | try: 132 | chat = await client.get_chat(grpid) 133 | title = chat.title 134 | except: 135 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 136 | return 137 | else: 138 | await message.reply_text("I'm not connected to any groups!", quote=True) 139 | return 140 | 141 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 142 | grp_id = message.chat.id 143 | title = message.chat.title 144 | 145 | else: 146 | return 147 | 148 | st = await client.get_chat_member(grp_id, userid) 149 | if ( 150 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 151 | and st.status != enums.ChatMemberStatus.OWNER 152 | and str(userid) not in ADMINS 153 | ): 154 | return 155 | 156 | texts = await get_filters(grp_id) 157 | count = await count_filters(grp_id) 158 | if count: 159 | filterlist = f"Total number of filters in **{title}** : {count}\n\n" 160 | 161 | for text in texts: 162 | keywords = " × `{}`\n".format(text) 163 | 164 | filterlist += keywords 165 | 166 | if len(filterlist) > 4096: 167 | with io.BytesIO(str.encode(filterlist.replace("`", ""))) as keyword_file: 168 | keyword_file.name = "keywords.txt" 169 | await message.reply_document( 170 | document=keyword_file, 171 | quote=True 172 | ) 173 | return 174 | else: 175 | filterlist = f"There are no active filters in **{title}**" 176 | 177 | await message.reply_text( 178 | text=filterlist, 179 | quote=True, 180 | parse_mode=enums.ParseMode.MARKDOWN 181 | ) 182 | 183 | @Client.on_message(filters.command('del') & filters.incoming) 184 | async def deletefilter(client, message): 185 | userid = message.from_user.id if message.from_user else None 186 | if not userid: 187 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 188 | chat_type = message.chat.type 189 | 190 | if chat_type == enums.ChatType.PRIVATE: 191 | grpid = await active_connection(str(userid)) 192 | if grpid is not None: 193 | grp_id = grpid 194 | try: 195 | chat = await client.get_chat(grpid) 196 | title = chat.title 197 | except: 198 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 199 | return 200 | else: 201 | await message.reply_text("I'm not connected to any groups!", quote=True) 202 | return 203 | 204 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 205 | grp_id = message.chat.id 206 | title = message.chat.title 207 | 208 | else: 209 | return 210 | 211 | st = await client.get_chat_member(grp_id, userid) 212 | if ( 213 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 214 | and st.status != enums.ChatMemberStatus.OWNER 215 | and str(userid) not in ADMINS 216 | ): 217 | return 218 | 219 | try: 220 | cmd, text = message.text.split(" ", 1) 221 | except: 222 | await message.reply_text( 223 | "Mention the filtername which you wanna delete!\n\n" 224 | "/del filtername\n\n" 225 | "Use /viewfilters to view all available filters", 226 | quote=True 227 | ) 228 | return 229 | 230 | query = text.lower() 231 | 232 | await delete_filter(message, query, grp_id) 233 | 234 | 235 | @Client.on_message(filters.command('delall') & filters.incoming) 236 | async def delallconfirm(client, message): 237 | userid = message.from_user.id if message.from_user else None 238 | if not userid: 239 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 240 | chat_type = message.chat.type 241 | 242 | if chat_type == enums.ChatType.PRIVATE: 243 | grpid = await active_connection(str(userid)) 244 | if grpid is not None: 245 | grp_id = grpid 246 | try: 247 | chat = await client.get_chat(grpid) 248 | title = chat.title 249 | except: 250 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 251 | return 252 | else: 253 | await message.reply_text("I'm not connected to any groups!", quote=True) 254 | return 255 | 256 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 257 | grp_id = message.chat.id 258 | title = message.chat.title 259 | 260 | else: 261 | return 262 | 263 | 264 | st = await client.get_chat_member(grp_id, userid) 265 | if (st.status == enums.ChatMemberStatus.OWNER) or (str(userid) in ADMINS): 266 | await message.reply_text( 267 | f"This will delete all filters from '{title}'.\nDo you want to continue??", 268 | reply_markup=InlineKeyboardMarkup([ 269 | [InlineKeyboardButton(text="YES",callback_data="delallconfirm")], 270 | [InlineKeyboardButton(text="CANCEL",callback_data="delallcancel")] 271 | ]), 272 | quote=True 273 | ) 274 | 275 | -------------------------------------------------------------------------------- /Script.py: -------------------------------------------------------------------------------- 1 | class script(object): 2 | START_TXT = """𝖸𝗈...𝖸𝗈... {} 💖 3 | 4 | 𝖨'𝗆 𝖯𝗈𝗐𝖾𝗋𝖿𝗎𝗅 𝖠𝗎𝗍𝗈-𝖥𝗂𝗅𝗍𝖾𝗋 𝖡𝗈𝗍 𝖸𝗈𝗎 𝖢𝖺𝗇 𝖴𝗌𝖾 𝖬𝖾 𝖠𝗌 𝖠 𝖠𝗎𝗍𝗈-𝖿𝗂𝗅𝗍𝖾𝗋 𝗂𝗇 𝖸𝗈𝗎𝗋 𝖦𝗋𝗈𝗎𝗉 5 | 6 | 𝖨𝗍𝗌 𝖤𝖺𝗌𝗒 𝖳𝗈 𝖴𝗌𝖾 𝖬𝖾; 𝖩𝗎𝗌𝗍 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖦𝗋𝗈𝗎𝗉 𝖠𝗌 𝖠𝖽𝗆𝗂𝗇, 7 | 𝖳𝗁𝖺𝗍𝗌 𝖠𝗅𝗅, 𝗂 𝗐𝗂𝗅𝗅 𝖯𝗋𝗈𝗏𝗂𝖽𝖾 𝖬𝗈𝗏𝗂𝖾𝗌 𝖳𝗁𝖾𝗋𝖾...🤓🤪 8 | 9 | ⚠️ 𝖬𝗈𝗋𝖾 𝖧𝖾𝗅𝗉 𝖧𝗂𝗍 /help 10 | 11 | 🙋🏻‍♂️ 𝖳𝗎𝗍𝗈𝗋𝗂𝖺𝗅 𝖦𝗎𝗂𝖽𝖾 @piro_tuts 12 | 13 | 😎 𝖯𝗈𝗐𝖾𝗋𝖾𝖽 𝖻𝗒 @piroxbots""" 14 | 15 | HELP_TXT = """🙋🏻‍♂️ 𝖧𝖾𝗅𝗅𝗈𝗈𝗈 {} 🤓 16 | 17 | ○ 𝗂𝗍'𝗌 𝖭𝗈𝗍𝖾 𝖢𝗈𝗆𝗉𝗅𝗂𝖼𝖺𝗍𝖾𝖽...🤓 18 | 19 | ○ 𝖲𝖾𝖺𝗋𝖼𝗁 𝗎𝗌𝗂𝗇𝗀 𝗂𝗇𝗅𝗂𝗇𝖾 𝗆𝗈𝖽𝖾 20 | 𝖳𝗁𝗂𝗌 𝗆𝖾𝗍𝗁𝗈𝖽 𝗐𝗈𝗋𝗄𝗌 𝗈𝗇 𝖺𝗇𝗒 𝖼𝗁𝖺𝗍, 𝖩𝗎𝗌𝗍 𝗍𝗒𝗉𝖾 Bot Username 𝖺𝗇𝖽 𝗍𝗁𝖾𝗇 𝗅𝖾𝖺𝗏𝖾 𝖺 𝗌𝗉𝖺𝖼𝖾 𝖺𝗇𝖽 𝗌𝖾𝖺𝗋𝖼𝗁 𝖺𝗇𝗒 𝗆𝗈𝗏𝗂𝖾 𝗒𝗈𝗎 𝗐𝖺𝗇𝗍... 21 | 22 | 🙋🏻‍♂️ 𝖳𝗎𝗍𝗈𝗋𝗂𝖺𝗅 𝖦𝗎𝗂𝖽𝖾 @piro_tuts 23 | 24 | ○ 𝖠𝗏𝖺𝗂𝗅𝖺𝖻𝗅𝖾 𝖢𝗈𝗆𝗆𝖺𝗇𝖽𝗌 25 | 26 | /alive - Check I'm Alive.. 27 | /info - User info 28 | /ping - To get your ping 29 | /id - User id 30 | /stats - Db status 31 | /broadcast - Broadcast (𝖮𝗐𝗇𝖾𝗋 𝖮𝗇𝗅𝗒) 32 | 33 | ○ 𝖭𝗈𝗍𝗂𝖼𝖾 📙:- 34 | 35 | 𝖣𝗈𝗇𝗍 𝖲𝗉𝖺𝗆 𝖬𝖾...🤒 36 | 37 | 😎 𝖯𝗈𝗐𝖾𝗋𝖾𝖽 𝖻𝗒 @piroxbots""" 38 | 39 | ABOUT_TXT = """○ 𝖬𝗒 𝖭𝖺𝗆𝖾: {} 40 | ○ 𝖢𝗋𝖾𝖺𝗍𝗈𝗋 : 𝖳𝗁𝗂𝗌 𝖯𝖾𝗋𝗌𝗈𝗇 41 | ○ 𝖫𝖺𝗇𝗀𝗎𝖺𝗀𝖾 : 𝖯𝗒𝗍𝗁𝗈𝗇 𝟥 42 | ○ 𝖫𝗂𝖻𝗋𝖺𝗋𝗒 : 𝖯𝗒𝗋𝗈𝗀𝗋𝖺𝗆 𝖺𝗌𝗒𝗇𝖼𝗂𝗈 𝟢.𝟣𝟩.𝟣 43 | ○ 𝖲𝖾𝗋𝗏𝖾𝗋 : Contabo 44 | ○ 𝖣𝖺𝗍𝖺𝖻𝖺𝗌𝖾 : 𝖬𝗈𝗇𝗀𝗈𝖣𝖡 𝖥𝗋𝖾𝖾 𝖳𝗂𝖾𝗋 45 | ○ 𝖡𝗎𝗂𝗅𝖽 𝖲𝗍𝖺𝗍𝗎𝗌 : v1.0.1 [BeTa] 46 | ○ 𝖲𝗎𝗉𝗉𝗈𝗋𝗍 𝖦𝗋𝗈𝗎𝗉 : 𝖳𝖺𝗉 𝖧𝖾𝗋𝖾""" 47 | 48 | SOURCE_TXT = """NOTE: 49 | Special Thanks to EvaMaria Devs & Cloners for the codes 50 | DEV: 51 | 52 | - [𝖯𝖨𝖱𝖮] 53 | 54 | - Source - https://github.com/ritheshrkrm/PiroAutoFilterBot""" #please don't change repo link give credit :) 55 | 56 | MANUELFILTER_TXT = """ʜᴇʟᴘ: ꜰɪʟᴛᴇʀꜱ 57 | - ꜰɪʟᴛᴇʀ ɪꜱ ᴀ ꜰᴇᴀᴛᴜʀᴇ ᴡᴇʀᴇ ᴜꜱᴇʀꜱ ᴄᴀɴ ꜱᴇᴛ ᴀᴜᴛᴏᴍᴀᴛᴇᴅ ʀᴇᴘʟɪᴇꜱ ꜰᴏʀ ᴀ ᴘᴀʀᴛɪᴄᴜʟᴀʀ ᴋᴇʏᴡᴏʀᴅ ᴀɴᴅ ɪ ᴡɪʟʟ ʀᴇꜱᴘᴏɴᴅ ᴡʜᴇɴᴇᴠᴇʀ ᴀ ᴋᴇʏᴡᴏʀᴅ ɪꜱ ꜰᴏᴜɴᴅ ɪɴ ᴛʜᴇ ᴍᴇꜱꜱᴀɢᴇ 58 | ɴᴏᴛᴇ: 59 | 1. ᴛʜɪꜱ ʙᴏᴛ ꜱʜᴏᴜʟᴅ ʜᴀᴠᴇ ᴀᴅᴍɪɴ ᴘʀɪᴠɪʟᴇɢᴇ. 60 | 2. ᴏɴʟʏ ᴀᴅᴍɪɴꜱ ᴄᴀɴ ᴀᴅᴅ ꜰɪʟᴛᴇʀꜱ ɪɴ ᴀ ᴄʜᴀᴛ. 61 | 3. ᴀʟᴇʀᴛ ʙᴜᴛᴛᴏɴꜱ ʜᴀᴠᴇ ᴀ ʟɪᴍɪᴛ ᴏꜰ 64 ᴄʜᴀʀᴀᴄᴛᴇʀꜱ. 62 | 63 | Cᴏᴍᴍᴀɴᴅs Aɴᴅ Usᴀɢᴇ: 64 | 65 | • /filter - ᴀᴅᴅ ᴀ ꜰɪʟᴛᴇʀ ɪɴ ᴀ ᴄʜᴀᴛ 66 | • /filters - ʟɪꜱᴛ ᴀʟʟ ᴛʜᴇ ꜰɪʟᴛᴇʀꜱ ᴏꜰ ᴀ ᴄʜᴀᴛ 67 | • /del - ᴅᴇʟᴇᴛᴇ ᴀ ꜱᴘᴇᴄɪꜰɪᴄ ꜰɪʟᴛᴇʀ ɪɴ ᴀ ᴄʜᴀᴛ 68 | • /delall - ᴅᴇʟᴇᴛᴇ ᴛʜᴇ ᴡʜᴏʟᴇ ꜰɪʟᴛᴇʀꜱ ɪɴ ᴀ ᴄʜᴀᴛ (ᴄʜᴀᴛ ᴏᴡɴᴇʀ ᴏɴʟʏ)""" 69 | 70 | BUTTON_TXT = """ʜᴇʟᴘ: ʙᴜᴛᴛᴏɴꜱ 71 | - ᴛʜɪꜱ ʙᴏᴛ ꜱᴜᴘᴘᴏʀᴛꜱ ʙᴏᴛʜ ᴜʀʟ ᴀɴᴅ ᴀʟᴇʀᴛ ɪɴʟɪɴᴇ ʙᴜᴛᴛᴏɴꜱ. 72 | ɴᴏᴛᴇ: 73 | 1. ᴛᴇʟᴇɢʀᴀᴍ ᴡɪʟʟ ɴᴏᴛ ᴀʟʟᴏᴡꜱ ʏᴏᴜ ᴛᴏ ꜱᴇɴᴅ ʙᴜᴛᴛᴏɴꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴄᴏɴᴛᴇɴᴛ, ꜱᴏ ᴄᴏɴᴛᴇɴᴛ ɪꜱ ᴍᴀɴᴅᴀᴛᴏʀʏ. 74 | 2. ᴛʜɪꜱ ʙᴏᴛ ꜱᴜᴘᴘᴏʀᴛꜱ ʙᴜᴛᴛᴏɴꜱ ᴡɪᴛʜ ᴀɴʏ ᴛᴇʟᴇɢʀᴀᴍ ᴍᴇᴅɪᴀ ᴛʏᴘᴇ. 75 | 3. ʙᴜᴛᴛᴏɴꜱ ꜱʜᴏᴜʟᴅ ʙᴇ ᴘʀᴏᴘᴇʀʟʏ ᴘᴀʀꜱᴇᴅ ᴀꜱ ᴍᴀʀᴋᴅᴏᴡɴ ꜰᴏʀᴍᴀᴛ 76 | ᴜʀʟ ʙᴜᴛᴛᴏɴꜱ: 77 | [Button Text](buttonurl:https://t.me/piroxbots) 78 | ᴀʟᴇʀᴛ ʙᴜᴛᴛᴏɴꜱ: 79 | [Button Text](buttonalert:ᴛʜɪꜱ ɪꜱ ᴀɴ ᴀʟᴇʀᴛ ᴍᴇꜱꜱᴀɢᴇ)""" 80 | 81 | AUTOFILTER_TXT = """ʜᴇʟᴘ: ᴀᴜᴛᴏ ꜰɪʟᴛᴇʀ 82 | ɴᴏᴛᴇ: Fɪʟᴇ Iɴᴅᴇx 83 | 1. ᴍᴀᴋᴇ ᴍᴇ ᴛʜᴇ ᴀᴅᴍɪɴ ᴏꜰ ʏᴏᴜʀ ᴄʜᴀɴɴᴇʟ ɪꜰ ɪᴛ'ꜱ ᴘʀɪᴠᴀᴛᴇ. 84 | 2. ᴍᴀᴋᴇ ꜱᴜʀᴇ ᴛʜᴀᴛ ʏᴏᴜʀ ᴄʜᴀɴɴᴇʟ ᴅᴏᴇꜱ ɴᴏᴛ ᴄᴏɴᴛᴀɪɴꜱ ᴄᴀᴍʀɪᴘꜱ, ᴘᴏʀɴ ᴀɴᴅ ꜰᴀᴋᴇ ꜰɪʟᴇꜱ. 85 | 3. ꜰᴏʀᴡᴀʀᴅ ᴛʜᴇ ʟᴀꜱᴛ ᴍᴇꜱꜱᴀɢᴇ ᴛᴏ ᴍᴇ ᴡɪᴛʜ Qᴜᴏᴛᴇꜱ. ɪ'ʟʟ ᴀᴅᴅ ᴀʟʟ ᴛʜᴇ ꜰɪʟᴇꜱ ɪɴ ᴛʜᴀᴛ ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴍʏ ᴅʙ. 86 | 87 | Nᴏᴛᴇ: AᴜᴛᴏFɪʟᴛᴇʀ 88 | 1. Aᴅᴅ ᴛʜᴇ ʙᴏᴛ ᴀs ᴀᴅᴍɪɴ ᴏɴ ʏᴏᴜʀ ɢʀᴏᴜᴘ. 89 | 2. Usᴇ /connect ᴀɴᴅ ᴄᴏɴɴᴇᴄᴛ ʏᴏᴜʀ ɢʀᴏᴜᴘ ᴛᴏ ᴛʜᴇ ʙᴏᴛ. 90 | 3. Usᴇ /settings ᴏɴ ʙᴏᴛ's PM ᴀɴᴅ ᴛᴜʀɴ ᴏɴ AᴜᴛᴏFɪʟᴛᴇʀ ᴏɴ ᴛʜᴇ sᴇᴛᴛɪɴɢs ᴍᴇɴᴜ.""" 91 | 92 | CONNECTION_TXT = """ʜᴇʟᴘ: ᴄᴏɴɴᴇᴄᴛɪᴏɴꜱ 93 | - ᴜꜱᴇᴅ ᴛᴏ ᴄᴏɴɴᴇᴄᴛ ʙᴏᴛ ᴛᴏ ᴘᴍ ꜰᴏʀ ᴍᴀɴᴀɢɪɴɢ ꜰɪʟᴛᴇʀꜱ 94 | - ɪᴛ ʜᴇʟᴘꜱ ᴛᴏ ᴀᴠᴏɪᴅ ꜱᴘᴀᴍᴍɪɴɢ ɪɴ ɢʀᴏᴜᴘꜱ. 95 | ɴᴏᴛᴇ: 96 | 1. ᴏɴʟʏ ᴀᴅᴍɪɴꜱ ᴄᴀɴ ᴀᴅᴅ ᴀ ᴄᴏɴɴᴇᴄᴛɪᴏɴ. 97 | 2. ꜱᴇɴᴅ /ᴄᴏɴɴᴇᴄᴛ ꜰᴏʀ ᴄᴏɴɴᴇᴄᴛɪɴɢ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ᴘᴍ 98 | Cᴏᴍᴍᴀɴᴅs Aɴᴅ Usᴀɢᴇ: 99 | • /connect - ᴄᴏɴɴᴇᴄᴛ ᴀ ᴘᴀʀᴛɪᴄᴜʟᴀʀ ᴄʜᴀᴛ ᴛᴏ ʏᴏᴜʀ ᴘᴍ 100 | • /disconnect - ᴅɪꜱᴄᴏɴɴᴇᴄᴛ ꜰʀᴏᴍ ᴀ ᴄʜᴀᴛ 101 | • /connections - ʟɪꜱᴛ ᴀʟʟ ʏᴏᴜʀ ᴄᴏɴɴᴇᴄᴛɪᴏɴꜱ""" 102 | 103 | EXTRAMOD_TXT = """ʜᴇʟᴘ: Exᴛʀᴀ Mᴏᴅᴜʟᴇs 104 | ɴᴏᴛᴇ: 105 | ᴛʜᴇꜱᴇ ᴀʀᴇ ᴛʜᴇ ᴇxᴛʀᴀ ꜰᴇᴀᴛᴜʀᴇꜱ ᴏꜰ ᴛʜɪꜱ ʙᴏᴛ 106 | Cᴏᴍᴍᴀɴᴅs Aɴᴅ Usᴀɢᴇ: 107 | • /id - ɢᴇᴛ ɪᴅ ᴏꜰ ᴀ ꜱᴘᴇᴄɪꜰɪᴇᴅ ᴜꜱᴇʀ. 108 | • /info - ɢᴇᴛ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ ᴀʙᴏᴜᴛ ᴀ ᴜꜱᴇʀ. 109 | • /imdb - ɢᴇᴛ ᴛʜᴇ ꜰɪʟᴍ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ ꜰʀᴏᴍ ɪᴍᴅʙ ꜱᴏᴜʀᴄᴇ. 110 | • /search - ɢᴇᴛ ᴛʜᴇ ꜰɪʟᴍ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ ꜰʀᴏᴍ ᴠᴀʀɪᴏᴜꜱ ꜱᴏᴜʀᴄᴇꜱ.""" 111 | 112 | ADMIN_TXT = """ʜᴇʟᴘ: Aᴅᴍɪɴ Mᴏᴅs 113 | ɴᴏᴛᴇ: 114 | Tʜɪs Mᴏᴅᴜʟᴇ Oɴʟʏ Wᴏʀᴋs Fᴏʀ Mʏ Aᴅᴍɪɴs 115 | Cᴏᴍᴍᴀɴᴅs Aɴᴅ Usᴀɢᴇ: 116 | • /logs - ᴛᴏ ɢᴇᴛ ᴛʜᴇ ʀᴇᴄᴇɴᴛ ᴇʀʀᴏʀꜱ 117 | • /stats - ᴛᴏ ɢᴇᴛ ꜱᴛᴀᴛᴜꜱ ᴏꜰ ꜰɪʟᴇꜱ ɪɴ ᴅʙ. [Tʜɪs Cᴏᴍᴍᴀɴᴅ Cᴀɴ Bᴇ Usᴇᴅ Bʏ Aɴʏᴏɴᴇ] 118 | • /delete - ᴛᴏ ᴅᴇʟᴇᴛᴇ ᴀ ꜱᴘᴇᴄɪꜰɪᴄ ꜰɪʟᴇ ꜰʀᴏᴍ ᴅʙ. 119 | • /users - ᴛᴏ ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴍʏ ᴜꜱᴇʀꜱ ᴀɴᴅ ɪᴅꜱ. 120 | • /chats - ᴛᴏ ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴍʏ ᴄʜᴀᴛꜱ ᴀɴᴅ ɪᴅꜱ 121 | • /leave - ᴛᴏ ʟᴇᴀᴠᴇ ꜰʀᴏᴍ ᴀ ᴄʜᴀᴛ. 122 | • /disable - ᴛᴏ ᴅɪꜱᴀʙʟᴇ ᴀ ᴄʜᴀᴛ. 123 | • /ban - ᴛᴏ ʙᴀɴ ᴀ ᴜꜱᴇʀ. 124 | • /unban - ᴛᴏ ᴜɴʙᴀɴ ᴀ ᴜꜱᴇʀ. 125 | • /channel - ᴛᴏ ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴛᴏᴛᴀʟ ᴄᴏɴɴᴇᴄᴛᴇᴅ ᴄʜᴀɴɴᴇʟꜱ 126 | • /broadcast - ᴛᴏ ʙʀᴏᴀᴅᴄᴀꜱᴛ ᴀ ᴍᴇꜱꜱᴀɢᴇ ᴛᴏ ᴀʟʟ ᴜꜱᴇʀꜱ 127 | • /group_broadcast - Tᴏ ʙʀᴏᴀᴅᴄᴀsᴛ ᴀ ᴍᴇssᴀɢᴇ ᴛᴏ ᴀʟʟ ᴄᴏɴɴᴇᴄᴛᴇᴅ ɢʀᴏᴜᴘs. 128 | • /gfilter - ᴛᴏ ᴀᴅᴅ ɢʟᴏʙᴀʟ ғɪʟᴛᴇʀs 129 | • /gfilters - ᴛᴏ ᴠɪᴇᴡ ʟɪsᴛ ᴏғ ᴀʟʟ ɢʟᴏʙᴀʟ ғɪʟᴛᴇʀs 130 | • /delg - ᴛᴏ ᴅᴇʟᴇᴛᴇ ᴀ sᴘᴇᴄɪғɪᴄ ɢʟᴏʙᴀʟ ғɪʟᴛᴇʀ 131 | • /request - Tᴏ sᴇɴᴅ ᴀ Mᴏᴠɪᴇ/Sᴇʀɪᴇs ʀᴇᴏ̨ᴜᴇsᴛ ᴛᴏ ʙᴏᴛ ᴀᴅᴍɪɴs. Oɴʟʏ ᴡᴏʀᴋs ᴏɴ sᴜᴘᴘᴏʀᴛ ɢʀᴏᴜᴘ. [Tʜɪs Cᴏᴍᴍᴀɴᴅ Cᴀɴ Bᴇ Usᴇᴅ Bʏ Aɴʏᴏɴᴇ] 132 | • /delallg - Tᴏ ᴅᴇʟᴇᴛᴇ ᴀʟʟ Gғɪʟᴛᴇʀs ғʀᴏᴍ ᴛʜᴇ ʙᴏᴛ's ᴅᴀᴛᴀʙᴀsᴇ. 133 | • /deletefiles - Tᴏ ᴅᴇʟᴇᴛᴇ CᴀᴍRɪᴘ ᴀɴᴅ PʀᴇDVD Fɪʟᴇs ғʀᴏᴍ ᴛʜᴇ ʙᴏᴛ's ᴅᴀᴛᴀʙᴀsᴇ.""" 134 | 135 | STATUS_TXT = """𝖳𝗈𝗍𝖺𝗅 𝖥𝗂𝗅𝖾𝗌: {} 136 | 𝖳𝗈𝗍𝖺𝗅 𝖬𝖾𝗆𝖻𝖾𝗋𝗌: {} 137 | 𝖳𝗈𝗍𝖺𝗅 𝖢𝗁𝖺𝗍𝗌: {} 138 | 𝖴𝗌𝖾𝖽 𝖲𝗍𝗈𝗋𝖺𝗀𝖾: {} 139 | 140 | 😎 𝖯𝗈𝗐𝖾𝗋𝖾𝖽 𝖻𝗒 @piroxbots""" 141 | 142 | LOG_TEXT_G = """#NewGroup 143 | 𝖦𝗋𝗈𝗎𝗉 = {}({}) 144 | 𝖳𝗈𝗍𝖺𝗅 𝖬𝖾𝗆𝖻𝖾𝗋𝗌 = {} 145 | 𝖠𝖽𝖽𝖾𝖽 𝖡𝗒 - {}""" 146 | 147 | LOG_TEXT_P = """#NewUser 148 | 𝖨𝖽 - {} 149 | 𝖭𝖺𝗆𝖾 - {}""" 150 | 151 | REQ_TXT = """𝖧𝖾𝗅𝗅𝗈 {} 152 | 𝖸𝗈𝗎𝗋 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 𝖧𝖺𝗌 𝖡𝖾𝖾𝗇 𝖠𝗉𝗉𝗋𝗈𝗏𝖾𝖽...!!!""" 153 | 154 | ALRT_TXT = """Hello {}, 155 | This is Not your Request 156 | Request Yourself...!!""" 157 | 158 | OLD_ALRT_TXT = """Hey {}, 159 | You are using one of old message, 160 | Request Again""" 161 | 162 | CUDNT_FND = """ 163 | 𝖨 𝖼𝗈𝗎𝗅𝖽𝗇'𝗍 𝖿𝗂𝗇𝖽 𝖺𝗇𝗒𝗍𝗁𝗂𝗇𝗀 𝗋𝖾𝗅𝖺𝗍𝖾𝖽 𝗍𝗈 𝗍𝗁𝖺𝗍 164 | 𝖣𝗂𝖽 𝗒𝗈𝗎 𝗆𝖾𝖺𝗇 𝖺𝗇𝗒 𝗈𝗇𝖾 𝗈𝖿 𝗍𝗁𝖾𝗌𝖾?""" 165 | 166 | I_CUDNT = """❌ 𝖨 𝖼𝗈𝗎𝗅𝖽𝗇'𝗍 𝖿𝗂𝗇𝖽 𝖺𝗇𝗒𝗍𝗁𝗂𝗇𝗀 𝗋𝖾𝗅𝖺𝗍𝖾𝖽 𝗍𝗈 𝗍𝗁𝖺𝗍\n\n‼ 𝖱𝖾𝗉𝗈𝗋𝗍 𝗍𝗈 𝖺𝖽𝗆𝗂𝗇 ▶ @raixchat""" 167 | 168 | I_CUD_NT = """❌ 𝖨 𝖼𝗈𝗎𝗅𝖽𝗇'𝗍 𝖿𝗂𝗇𝖽 𝖺𝗇𝗒𝗍𝗁𝗂𝗇𝗀 𝗋𝖾𝗅𝖺𝗍𝖾𝖽 𝗍𝗈 𝗍𝗁𝖺𝗍\n\n‼ 𝖱𝖾𝗉𝗈𝗋𝗍 𝗍𝗈 𝖺𝖽𝗆𝗂𝗇 ▶ @raixchat""" 169 | 170 | MVE_NT_FND = """❌ 𝖨 𝖼𝗈𝗎𝗅𝖽𝗇'𝗍 𝖿𝗂𝗇𝖽 𝖺𝗇𝗒𝗍𝗁𝗂𝗇𝗀 𝗋𝖾𝗅𝖺𝗍𝖾𝖽 𝗍𝗈 𝗍𝗁𝖺𝗍\n\n‼ 𝖱𝖾𝗉𝗈𝗋𝗍 𝗍𝗈 𝖺𝖽𝗆𝗂𝗇 ▶ @raixchat""" 171 | 172 | TOP_ALRT_MSG = """𝖢𝗁𝖾𝖼𝗄𝗂𝗇𝗀 𝖿𝗈𝗋 𝗊𝗎𝖾𝗋𝗒 𝗂𝗇 𝖣𝖺𝗍𝖺𝖻𝖺𝗌𝖾...""" 173 | 174 | MELCOW_ENG = """Hey {}, Welcome to {} 175 | 176 | • 𝖭𝗈 𝖯𝗋𝗈𝗆𝗈, 𝖭𝗈 𝖯𝗈𝗋𝗇, 𝖭𝗈 𝖮𝗍𝗁𝖾𝗋 𝖠𝖻𝗎𝗌𝖾𝗌 177 | • 𝖠𝗌𝗄 𝖸𝗈𝗎𝗋 𝖬𝗈𝗏𝗂𝖾𝗌 𝖶𝗂𝗍𝗁 𝖢𝗈𝗋𝗋𝖾𝖼𝗍 𝖲𝗉𝖾𝗅𝗅𝗂𝗇𝗀 178 | • 𝖲𝗉𝖺𝗆𝗆𝖾𝗋𝗌 𝖲𝗍𝖺𝗒 𝖠𝗐𝖺𝗒 179 | • 𝖥𝖾𝖾𝗅 𝖥𝗋𝖾𝖾 𝖳𝗈 𝖱𝖾𝗉𝗈𝗋𝗍 𝖠𝗇𝗒 𝖤𝗋𝗋𝗈𝗋𝗌 𝖳𝗈 𝖠𝖽𝗆𝗂𝗇𝗌 𝗎𝗌𝗂𝗇𝗀 @admin 180 | 181 | 𝗥𝗲𝗾𝘂𝗲𝘀𝘁𝘀 𝗙𝗼𝗿𝗺𝗮𝘁𝘀 182 | 183 | • 𝖲𝗈𝗅𝗈 2017 184 | • 𝖣𝗁𝗈𝗈𝗆 3 𝖧𝗂𝗇𝖽𝗂 185 | • 𝖪𝗎𝗋𝗎𝗉 𝖪𝖺𝗇 186 | • 𝖣𝖺𝗋𝗄 𝗌01 187 | • 𝖲𝗁𝖾 𝖧𝗎𝗅𝗄 720𝗉 188 | • 𝖥𝗋𝗂𝖾𝗇𝖽𝗌 𝗌03 1080𝗉 189 | • 𝖬𝗎𝗌𝗍 𝗋𝖾𝖺𝖽 𝗍𝗁𝗂𝗌 https://te.legra.ph/𝖯𝗈𝗐𝖾𝗋𝖾𝖽-𝖡𝗒-𝖯𝖨𝖱𝖮-12-11-2 190 | 191 | ‼️𝗗𝗼𝗻𝘁 𝗮𝗱𝗱 𝘄𝗼𝗿𝗱𝘀 & 𝘀𝘆𝗺𝗯𝗼𝗹𝘀 𝗹𝗶𝗸𝗲 , . - send link movie series 𝗲𝘁𝗰‼️""" 192 | 193 | OWNER_INFO = """ 194 | ○ 𝖢𝗋𝖾𝖺𝗍𝗈𝗋 : 𝖳𝗁𝗂𝗌 𝖯𝖾𝗋𝗌𝗈𝗇 195 | 196 | ○ 𝖲𝗎𝗉𝗉𝗈𝗋𝗍 𝖦𝗋𝗈𝗎𝗉 : 𝖳𝖺𝗉 𝖧𝖾𝗋𝖾 197 | """ 198 | 199 | NORSLTS = """ 200 | #NoResults 201 | 202 | ID : {} 203 | 204 | Name : {} 205 | 206 | Message : {}""" 207 | 208 | CAPTION = """ 209 | 📂 File Name: {file_name} 210 | 211 | ❤️‍🔥 Join [𝗕𝗟𝗔𝗦𝗧𝗘𝗥 𝗟𝗜𝗡𝗞𝗭](https://t.me/blaster_linkz) 212 | """ 213 | 214 | IMDB_TEMPLATE_TXT = """ 215 | 🏷 𝖳𝗂𝗍𝗅𝖾: {title} 216 | 🔮 𝖸𝖾𝖺𝗋: {year} \n⭐️ 𝖱𝖺𝗍𝗂𝗇𝗀𝗌: {rating}/ 10 217 | 🎭 𝖦𝖾𝗇𝖾𝗋𝗌: {genres} 218 | 219 | 🎊 𝖯𝗈𝗐𝖾𝗋𝖾𝖽 𝖡𝗒 [[𝖯𝖨𝖱𝖮]](t.me/piroxbots)""" 220 | 221 | ALL_FILTERS = """ 222 | Hᴇʏ {}, Tʜᴇsᴇ ᴀʀᴇ ᴍʏ ᴛʜʀᴇᴇ ᴛʏᴘᴇs ᴏғ ғɪʟᴛᴇʀs.""" 223 | 224 | GFILTER_TXT = """ 225 | Wᴇʟᴄᴏᴍᴇ ᴛᴏ Gʟᴏʙᴀʟ Fɪʟᴛᴇʀs. Gʟᴏʙᴀʟ Fɪʟᴛᴇʀs ᴀʀᴇ ᴛʜᴇ ғɪʟᴛᴇʀs sᴇᴛ ʙʏ ʙᴏᴛ ᴀᴅᴍɪɴs ᴡʜɪᴄʜ ᴡɪʟʟ ᴡᴏʀᴋ ᴏɴ ᴀʟʟ ɢʀᴏᴜᴘs. 226 | 227 | Aᴠᴀɪʟᴀʙʟᴇ ᴄᴏᴍᴍᴀɴᴅs: 228 | • /gfilter - Tᴏ ᴄʀᴇᴀᴛᴇ ᴀ ɢʟᴏʙᴀʟ ғɪʟᴛᴇʀ. 229 | • /gfilters - Tᴏ ᴠɪᴇᴡ ᴀʟʟ ɢʟᴏʙᴀʟ ғɪʟᴛᴇʀs. 230 | • /delg - Tᴏ ᴅᴇʟᴇᴛᴇ ᴀ ᴘᴀʀᴛɪᴄᴜʟᴀʀ ɢʟᴏʙᴀʟ ғɪʟᴛᴇʀ. 231 | • /delallg - ᴛᴏ ᴅᴇʟᴇᴛᴇ ᴀʟʟ ɢʟᴏʙᴀʟ ꜰɪʟᴛᴇʀꜱ.""" 232 | 233 | FILE_STORE_TXT = """ 234 | Fɪʟᴇ sᴛᴏʀᴇ ɪs ᴛʜᴇ ғᴇᴀᴛᴜʀᴇ ᴡʜɪᴄʜ ᴡɪʟʟ ᴄʀᴇᴀᴛᴇ ᴀ sʜᴀʀᴇᴀʙʟᴇ ʟɪɴᴋ ᴏғ ᴀ sɪɴɢʟᴇ ᴏʀ ᴍᴜʟᴛɪᴘʟᴇ ғɪʟᴇs. 235 | 236 | Aᴠᴀɪʟᴀʙʟᴇ ᴄᴏᴍᴍᴀɴᴅs: 237 | • /batch - Tᴏ ᴄʀᴇᴀᴛᴇ ᴀ ʙᴀᴛᴄʜ ʟɪɴᴋ ᴏғ ᴍᴜʟᴛɪᴘʟᴇ ғɪʟᴇs. 238 | • /link - Tᴏ ᴄʀᴇᴀᴛᴇ ᴀ sɪɴɢʟᴇ ғɪʟᴇ sᴛᴏʀᴇ ʟɪɴᴋ. 239 | • /pbatch - Jᴜsᴛ ʟɪᴋᴇ /batch, ʙᴜᴛ ᴛʜᴇ ғɪʟᴇs ᴡɪʟʟ ʙᴇ sᴇɴᴅ ᴡɪᴛʜ ғᴏʀᴡᴀʀᴅ ʀᴇsᴛʀɪᴄᴛɪᴏɴs. 240 | • /plink - Jᴜsᴛ ʟɪᴋᴇ /link, ʙᴜᴛ ᴛʜᴇ ғɪʟᴇ ᴡɪʟʟ ʙᴇ sᴇɴᴅ ᴡɪᴛʜ ғᴏʀᴡᴀʀᴅ ʀᴇsᴛʀɪᴄᴛɪᴏɴ.""" 241 | 242 | RESTART_TXT = """ 243 | 𝖡𝗈𝗍 𝖱𝖾𝗌𝗍𝖺𝗋𝗍𝖾𝖽 ! 244 | 245 | 📅 𝖣𝖺𝗍𝖾 : {} 246 | ⏰ 𝖳𝗂𝗆𝖾 : {} 247 | 🌐 𝖳𝗂𝗆𝖾𝗓𝗈𝗇𝖾 : Asia/Kolkata 248 | 🛠️ 𝖡𝗎𝗂𝗅𝖽 𝖲𝗍𝖺𝗍𝗎𝗌 : 𝗏2.7.3 [ 𝖲𝗍𝖺𝖻𝗅𝖾 ]""" 249 | 250 | RESTART_GC_TXT = """ 251 | 𝖡𝗈𝗍 𝖱𝖾𝗌𝗍𝖺𝗋𝗍𝖾𝖽 ✅""" 252 | 253 | LOGO = """ 254 | PIRO BOTS""" 255 | -------------------------------------------------------------------------------- /plugins/p_ttishow.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters, enums 2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery 3 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong, PeerIdInvalid 4 | from info import ADMINS, LOG_CHANNEL, SUPPORT_CHAT, MELCOW_VID 5 | from database.users_chats_db import db 6 | from database.ia_filterdb import Media 7 | from utils import get_size, temp, get_settings 8 | from Script import script 9 | from pyrogram.errors import ChatAdminRequired 10 | import asyncio 11 | 12 | 13 | 14 | @Client.on_message(filters.new_chat_members & filters.group) 15 | async def save_group(bot, message): 16 | r_j_check = [u.id for u in message.new_chat_members] 17 | if temp.ME in r_j_check: 18 | if not await db.get_chat(message.chat.id): 19 | total=await bot.get_chat_members_count(message.chat.id) 20 | r_j = message.from_user.mention if message.from_user else "Anonymous" 21 | await bot.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, r_j)) 22 | await db.add_chat(message.chat.id, message.chat.title) 23 | if message.chat.id in temp.BANNED_CHATS: 24 | buttons = [[ 25 | InlineKeyboardButton('🌐 𝖲𝗎𝗉𝗉𝗈𝗋𝗍 🌐', url=f"https://t.me/{SUPPORT_CHAT}") 26 | ]] 27 | reply_markup=InlineKeyboardMarkup(buttons) 28 | k = await message.reply( 29 | text='CHAT NOT ALLOWED 🐞\n\nMy admins has restricted me from working here ! If you want to know more about it contact support..', 30 | reply_markup=reply_markup, 31 | ) 32 | 33 | try: 34 | await k.pin() 35 | except: 36 | pass 37 | await bot.leave_chat(message.chat.id) 38 | return 39 | buttons = [[ 40 | InlineKeyboardButton('🧩 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 🧩', url=f"https://t.me/{SUPPORT_CHAT}"), 41 | InlineKeyboardButton('⚡𝖴𝗉𝖽𝖺𝗍𝖾𝗌 ⚡', url=f"https://t.me/piroxbots") 42 | ]] 43 | reply_markup=InlineKeyboardMarkup(buttons) 44 | await message.reply_text( 45 | text=f"Thankyou For Adding Me In {message.chat.title} ❣️\n\nIf you have any questions & doubts about using me contact 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 GROUP.", 46 | reply_markup=reply_markup) 47 | else: 48 | settings = await get_settings(message.chat.id) 49 | if settings["welcome"]: 50 | for u in message.new_chat_members: 51 | if (temp.MELCOW).get('welcome') is not None: 52 | try: 53 | await (temp.MELCOW['welcome']).delete() 54 | except: 55 | pass 56 | temp.MELCOW['welcome'] = await message.reply_video( 57 | video=(MELCOW_VID), 58 | caption=(script.MELCOW_ENG.format(u.mention, message.chat.title)), 59 | reply_markup=InlineKeyboardMarkup( 60 | [[ 61 | InlineKeyboardButton('🧩 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 🧩', url=f"https://t.me/{SUPPORT_CHAT}"), 62 | InlineKeyboardButton('⚡𝖴𝗉𝖽𝖺𝗍𝖾𝗌 ⚡', url=f"https://t.me/piroxbots") 63 | ]] 64 | ), 65 | parse_mode=enums.ParseMode.HTML 66 | ) 67 | 68 | if settings["auto_delete"]: 69 | await asyncio.sleep(300) 70 | await (temp.MELCOW['welcome']).delete() 71 | 72 | 73 | 74 | 75 | 76 | @Client.on_message(filters.command('leave') & filters.user(ADMINS)) 77 | async def leave_a_chat(bot, message): 78 | if len(message.command) == 1: 79 | return await message.reply('Give me a chat id') 80 | chat = message.command[1] 81 | try: 82 | chat = int(chat) 83 | except: 84 | chat = chat 85 | try: 86 | buttons = [[ 87 | InlineKeyboardButton('🧩 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 🧩', url=f"https://t.me/{SUPPORT_CHAT}"), 88 | InlineKeyboardButton('⚡𝖴𝗉𝖽𝖺𝗍𝖾𝗌 ⚡', url=f"https://t.me/piroxbots") 89 | ]] 90 | reply_markup=InlineKeyboardMarkup(buttons) 91 | await bot.send_message( 92 | chat_id=chat, 93 | text='Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 GROUP.', 94 | reply_markup=reply_markup, 95 | ) 96 | 97 | await bot.leave_chat(chat) 98 | await message.reply(f"left the chat `{chat}`") 99 | except Exception as e: 100 | await message.reply(f'Error - {e}') 101 | 102 | @Client.on_message(filters.command('disable') & filters.user(ADMINS)) 103 | async def disable_chat(bot, message): 104 | if len(message.command) == 1: 105 | return await message.reply('Give me a chat id') 106 | r = message.text.split(None) 107 | if len(r) > 2: 108 | reason = message.text.split(None, 2)[2] 109 | chat = message.text.split(None, 2)[1] 110 | else: 111 | chat = message.command[1] 112 | reason = "No reason Provided" 113 | try: 114 | chat_ = int(chat) 115 | except: 116 | return await message.reply('Give Me A Valid Chat ID') 117 | cha_t = await db.get_chat(int(chat_)) 118 | if not cha_t: 119 | return await message.reply("Chat Not Found In DB") 120 | if cha_t['is_disabled']: 121 | return await message.reply(f"This chat is already disabled:\nReason- {cha_t['reason']} ") 122 | await db.disable_chat(int(chat_), reason) 123 | temp.BANNED_CHATS.append(int(chat_)) 124 | await message.reply('Chat Successfully Disabled') 125 | try: 126 | buttons = [[ 127 | InlineKeyboardButton('🧩 𝖲𝖴𝖯𝖯𝖮𝖱𝖳 🧩', url=f"https://t.me/{SUPPORT_CHAT}"), 128 | InlineKeyboardButton('⚡𝖴𝗉𝖽𝖺𝗍𝖾𝗌 ⚡', url=f"https://t.me/piroxbots") 129 | ]] 130 | reply_markup=InlineKeyboardMarkup(buttons) 131 | await bot.send_message( 132 | chat_id=chat_, 133 | text=f'𝖧𝖾𝗅𝗅𝗈 𝖥𝗋𝗂𝖾𝗇𝖽𝗌, \n𝖬𝗒 𝖺𝖽𝗆𝗂𝗇 𝗁𝖺𝗌 𝗍𝗈𝗅𝖽 𝗆𝖾 𝗍𝗈 𝗅𝖾𝖺𝗏𝖾 𝖿𝗋𝗈𝗆 𝗀𝗋𝗈𝗎𝗉 𝗌𝗈 𝗂 𝗀𝗈! 𝖨𝖿 𝗒𝗈𝗎 𝗐𝖺𝗇𝗇𝖺 𝖺𝖽𝖽 𝗆𝖾 𝖺𝗀𝖺𝗂𝗇 𝖼𝗈𝗇𝗍𝖺𝖼𝗍 𝗆𝗒 𝗌𝗎𝗉𝗉𝗈𝗋𝗍 𝗀𝗋𝗈𝗎𝗉. \nReason : {reason}', 134 | reply_markup=reply_markup) 135 | await bot.leave_chat(chat_) 136 | except Exception as e: 137 | await message.reply(f"Error - {e}") 138 | 139 | 140 | @Client.on_message(filters.command('enable') & filters.user(ADMINS)) 141 | async def re_enable_chat(bot, message): 142 | if len(message.command) == 1: 143 | return await message.reply('Give me a chat id') 144 | chat = message.command[1] 145 | try: 146 | chat_ = int(chat) 147 | except: 148 | return await message.reply('Give Me A Valid Chat ID') 149 | sts = await db.get_chat(int(chat)) 150 | if not sts: 151 | return await message.reply("Chat Not Found In DB !") 152 | if not sts.get('is_disabled'): 153 | return await message.reply('This chat is not yet disabled.') 154 | await db.re_enable_chat(int(chat_)) 155 | temp.BANNED_CHATS.remove(int(chat_)) 156 | await message.reply("Chat Successfully re-enabled") 157 | 158 | 159 | @Client.on_message(filters.command('stats') & filters.incoming) 160 | async def get_ststs(bot, message): 161 | rju = await message.reply('Fetching stats...') 162 | total_users = await db.total_users_count() 163 | totl_chats = await db.total_chat_count() 164 | files = await Media.count_documents() 165 | size = await db.get_db_size() 166 | free = 536870912 - size 167 | size = get_size(size) 168 | free = get_size(free) 169 | await rju.edit(script.STATUS_TXT.format(files, total_users, totl_chats, size, free)) 170 | 171 | @Client.on_message(filters.command('invite') & filters.user(ADMINS)) 172 | async def gen_invite(bot, message): 173 | if len(message.command) == 1: 174 | return await message.reply('Give me a chat id') 175 | chat = message.command[1] 176 | try: 177 | chat = int(chat) 178 | except: 179 | return await message.reply('Give Me A Valid Chat ID') 180 | try: 181 | link = await bot.create_chat_invite_link(chat) 182 | except ChatAdminRequired: 183 | return await message.reply("Invite Link Generation Failed, Iam Not Having Sufficient Rights") 184 | except Exception as e: 185 | return await message.reply(f'Error {e}') 186 | await message.reply(f'Here is your Invite Link {link.invite_link}') 187 | 188 | @Client.on_message(filters.command('ban') & filters.user(ADMINS)) 189 | async def ban_a_user(bot, message): 190 | if len(message.command) == 1: 191 | return await message.reply('Give me a user id / username') 192 | r = message.text.split(None) 193 | if len(r) > 2: 194 | reason = message.text.split(None, 2)[2] 195 | chat = message.text.split(None, 2)[1] 196 | else: 197 | chat = message.command[1] 198 | reason = "No reason Provided" 199 | try: 200 | chat = int(chat) 201 | except: 202 | pass 203 | try: 204 | k = await bot.get_users(chat) 205 | except PeerIdInvalid: 206 | return await message.reply("This is an invalid user, make sure ia have met him before.") 207 | except IndexError: 208 | return await message.reply("This might be a channel, make sure its a user.") 209 | except Exception as e: 210 | return await message.reply(f'Error - {e}') 211 | else: 212 | jar = await db.get_ban_status(k.id) 213 | if jar['is_banned']: 214 | return await message.reply(f"{k.mention} is already banned\nReason: {jar['ban_reason']}") 215 | await db.ban_user(k.id, reason) 216 | temp.BANNED_USERS.append(k.id) 217 | await message.reply(f"Successfully banned {k.mention}") 218 | 219 | 220 | 221 | @Client.on_message(filters.command('unban') & filters.user(ADMINS)) 222 | async def unban_a_user(bot, message): 223 | if len(message.command) == 1: 224 | return await message.reply('Give me a user id / username') 225 | r = message.text.split(None) 226 | if len(r) > 2: 227 | reason = message.text.split(None, 2)[2] 228 | chat = message.text.split(None, 2)[1] 229 | else: 230 | chat = message.command[1] 231 | reason = "No reason Provided" 232 | try: 233 | chat = int(chat) 234 | except: 235 | pass 236 | try: 237 | k = await bot.get_users(chat) 238 | except PeerIdInvalid: 239 | return await message.reply("This is an invalid user, make sure ia have met him before.") 240 | except IndexError: 241 | return await message.reply("Thismight be a channel, make sure its a user.") 242 | except Exception as e: 243 | return await message.reply(f'Error - {e}') 244 | else: 245 | jar = await db.get_ban_status(k.id) 246 | if not jar['is_banned']: 247 | return await message.reply(f"{k.mention} is not yet banned.") 248 | await db.remove_ban(k.id) 249 | temp.BANNED_USERS.remove(k.id) 250 | await message.reply(f"Successfully unbanned {k.mention}") 251 | 252 | 253 | 254 | @Client.on_message(filters.command('users') & filters.user(ADMINS)) 255 | async def list_users(bot, message): 256 | raju = await message.reply('Getting List Of Users') 257 | users = await db.get_all_users() 258 | out = "Users Saved In DB Are:\n\n" 259 | async for user in users: 260 | out += f"{user['name']}" 261 | if user['ban_status']['is_banned']: 262 | out += '( Banned User )' 263 | out += '\n' 264 | try: 265 | await raju.edit_text(out) 266 | except MessageTooLong: 267 | with open('users.txt', 'w+') as outfile: 268 | outfile.write(out) 269 | await message.reply_document('users.txt', caption="List Of Users") 270 | 271 | @Client.on_message(filters.command('chats') & filters.user(ADMINS)) 272 | async def list_chats(bot, message): 273 | raju = await message.reply('Getting List Of chats') 274 | chats = await db.get_all_chats() 275 | out = "Chats Saved In DB Are:\n\n" 276 | async for chat in chats: 277 | out += f"**Title:** `{chat['title']}`\n**- ID:** `{chat['id']}`" 278 | if chat['chat_status']['is_disabled']: 279 | out += '( Disabled Chat )' 280 | out += '\n' 281 | try: 282 | await raju.edit_text(out) 283 | except MessageTooLong: 284 | with open('chats.txt', 'w+') as outfile: 285 | outfile.write(out) 286 | await message.reply_document('chats.txt', caption="List Of Chats") -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyrogram.errors import InputUserDeactivated, UserNotParticipant, FloodWait, UserIsBlocked, PeerIdInvalid 3 | from info import AUTH_CHANNEL, LONG_IMDB_DESCRIPTION, MAX_LIST_ELM, CUSTOM_FILE_CAPTION 4 | from imdb import Cinemagoer 5 | import asyncio 6 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup 7 | from pyrogram import enums 8 | from typing import Union 9 | import random 10 | import re 11 | import os 12 | from datetime import datetime 13 | from typing import List 14 | from database.users_chats_db import db 15 | from bs4 import BeautifulSoup 16 | import requests 17 | 18 | logger = logging.getLogger(__name__) 19 | logger.setLevel(logging.INFO) 20 | 21 | BTN_URL_REGEX = re.compile( 22 | r"(\[([^\[]+?)\]\((buttonurl|buttonalert):(?:/{0,2})(.+?)(:same)?\))" 23 | ) 24 | 25 | imdb = Cinemagoer() 26 | 27 | BANNED = {} 28 | SMART_OPEN = '“' 29 | SMART_CLOSE = '”' 30 | START_CHAR = ('\'', '"', SMART_OPEN) 31 | 32 | # temp db for banned 33 | class temp(object): 34 | BANNED_USERS = [] 35 | BANNED_CHATS = [] 36 | ME = None 37 | CURRENT=int(os.environ.get("SKIP", 2)) 38 | CANCEL = False 39 | MELCOW = {} 40 | FILES = {} 41 | U_NAME = None 42 | B_NAME = None 43 | SETTINGS = {} 44 | FILES_IDS = {} 45 | SPELL_CHECK = {} 46 | 47 | async def is_subscribed(bot, query): 48 | try: 49 | user = await bot.get_chat_member(AUTH_CHANNEL, query.from_user.id) 50 | except UserNotParticipant: 51 | pass 52 | except Exception as e: 53 | logger.exception(e) 54 | else: 55 | if user.status != enums.ChatMemberStatus.BANNED: 56 | return True 57 | 58 | return False 59 | 60 | async def get_poster(query, bulk=False, id=False, file=None): 61 | if not id: 62 | query = (query.strip()).lower() 63 | title = query 64 | year = re.findall(r'[1-2]\d{3}$', query, re.IGNORECASE) 65 | if year: 66 | year = list_to_str(year[:1]) 67 | title = (query.replace(year, "")).strip() 68 | elif file is not None: 69 | year = re.findall(r'[1-2]\d{3}', file, re.IGNORECASE) 70 | if year: 71 | year = list_to_str(year[:1]) 72 | else: 73 | year = None 74 | movieid = imdb.search_movie(title.lower(), results=10) 75 | if not movieid: 76 | return None 77 | if year: 78 | filtered=list(filter(lambda k: str(k.get('year')) == str(year), movieid)) 79 | if not filtered: 80 | filtered = movieid 81 | else: 82 | filtered = movieid 83 | movieid=list(filter(lambda k: k.get('kind') in ['movie', 'tv series'], filtered)) 84 | if not movieid: 85 | movieid = filtered 86 | if bulk: 87 | return movieid 88 | movieid = movieid[0].movieID 89 | else: 90 | movieid = query 91 | movie = imdb.get_movie(movieid) 92 | if movie.get("original air date"): 93 | date = movie["original air date"] 94 | elif movie.get("year"): 95 | date = movie.get("year") 96 | else: 97 | date = "N/A" 98 | plot = "" 99 | if not LONG_IMDB_DESCRIPTION: 100 | plot = movie.get('plot') 101 | if plot and len(plot) > 0: 102 | plot = plot[0] 103 | else: 104 | plot = movie.get('plot outline') 105 | if plot and len(plot) > 800: 106 | plot = plot[0:800] + "..." 107 | 108 | return { 109 | 'title': movie.get('title'), 110 | 'votes': movie.get('votes'), 111 | "aka": list_to_str(movie.get("akas")), 112 | "seasons": movie.get("number of seasons"), 113 | "box_office": movie.get('box office'), 114 | 'localized_title': movie.get('localized title'), 115 | 'kind': movie.get("kind"), 116 | "imdb_id": f"tt{movie.get('imdbID')}", 117 | "cast": list_to_str(movie.get("cast")), 118 | "runtime": list_to_str(movie.get("runtimes")), 119 | "countries": list_to_str(movie.get("countries")), 120 | "certificates": list_to_str(movie.get("certificates")), 121 | "languages": list_to_str(movie.get("languages")), 122 | "director": list_to_str(movie.get("director")), 123 | "writer":list_to_str(movie.get("writer")), 124 | "producer":list_to_str(movie.get("producer")), 125 | "composer":list_to_str(movie.get("composer")) , 126 | "cinematographer":list_to_str(movie.get("cinematographer")), 127 | "music_team": list_to_str(movie.get("music department")), 128 | "distributors": list_to_str(movie.get("distributors")), 129 | 'release_date': date, 130 | 'year': movie.get('year'), 131 | 'genres': list_to_str(movie.get("genres")), 132 | 'poster': movie.get('full-size cover url'), 133 | 'plot': plot, 134 | 'rating': str(movie.get("rating")), 135 | 'url':f'https://www.imdb.com/title/tt{movieid}' 136 | } 137 | 138 | async def broadcast_messages(user_id, message): 139 | try: 140 | await message.copy(chat_id=user_id) 141 | return True, "Success" 142 | except FloodWait as e: 143 | await asyncio.sleep(e.x) 144 | return await broadcast_messages(user_id, message) 145 | except InputUserDeactivated: 146 | await db.delete_user(int(user_id)) 147 | logging.info(f"{user_id}-Removed from Database, since deleted account.") 148 | return False, "Deleted" 149 | except UserIsBlocked: 150 | logging.info(f"{user_id} -Blocked the bot.") 151 | return False, "Blocked" 152 | except PeerIdInvalid: 153 | await db.delete_user(int(user_id)) 154 | logging.info(f"{user_id} - PeerIdInvalid") 155 | return False, "Error" 156 | except Exception as e: 157 | return False, "Error" 158 | 159 | async def broadcast_messages_group(chat_id, message): 160 | try: 161 | kd = await message.copy(chat_id=chat_id) 162 | try: 163 | await kd.pin() 164 | except: 165 | pass 166 | return True, "Succes" 167 | except FloodWait as e: 168 | await asyncio.sleep(e.x) 169 | return await broadcast_messages_group(chat_id, message) 170 | except Exception as e: 171 | return False, "Error" 172 | 173 | async def search_gagala(text): 174 | usr_agent = { 175 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 176 | 'Chrome/61.0.3163.100 Safari/537.36' 177 | } 178 | text = text.replace(" ", '+') 179 | url = f'https://www.google.com/search?q={text}' 180 | response = requests.get(url, headers=usr_agent) 181 | response.raise_for_status() 182 | soup = BeautifulSoup(response.text, 'html.parser') 183 | titles = soup.find_all( 'h3' ) 184 | return [title.getText() for title in titles] 185 | 186 | 187 | async def get_settings(group_id): 188 | settings = temp.SETTINGS.get(group_id) 189 | if not settings: 190 | settings = await db.get_settings(group_id) 191 | temp.SETTINGS[group_id] = settings 192 | return settings 193 | 194 | async def save_group_settings(group_id, key, value): 195 | current = await get_settings(group_id) 196 | current[key] = value 197 | temp.SETTINGS[group_id] = current 198 | await db.update_settings(group_id, current) 199 | 200 | def get_size(size): 201 | """Get size in readable format""" 202 | 203 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"] 204 | size = float(size) 205 | i = 0 206 | while size >= 1024.0 and i < len(units): 207 | i += 1 208 | size /= 1024.0 209 | return "%.2f %s" % (size, units[i]) 210 | 211 | def split_list(l, n): 212 | for i in range(0, len(l), n): 213 | yield l[i:i + n] 214 | 215 | def get_file_id(msg: Message): 216 | if msg.media: 217 | for message_type in ( 218 | "photo", 219 | "animation", 220 | "audio", 221 | "document", 222 | "video", 223 | "video_note", 224 | "voice", 225 | "sticker" 226 | ): 227 | obj = getattr(msg, message_type) 228 | if obj: 229 | setattr(obj, "message_type", message_type) 230 | return obj 231 | 232 | def extract_user(message: Message) -> Union[int, str]: 233 | """extracts the user from a message""" 234 | user_id = None 235 | user_first_name = None 236 | if message.reply_to_message: 237 | user_id = message.reply_to_message.from_user.id 238 | user_first_name = message.reply_to_message.from_user.first_name 239 | 240 | elif len(message.command) > 1: 241 | if ( 242 | len(message.entities) > 1 and 243 | message.entities[1].type == enums.MessageEntityType.TEXT_MENTION 244 | ): 245 | 246 | required_entity = message.entities[1] 247 | user_id = required_entity.user.id 248 | user_first_name = required_entity.user.first_name 249 | else: 250 | user_id = message.command[1] 251 | # don't want to make a request -_- 252 | user_first_name = user_id 253 | try: 254 | user_id = int(user_id) 255 | except ValueError: 256 | pass 257 | else: 258 | user_id = message.from_user.id 259 | user_first_name = message.from_user.first_name 260 | return (user_id, user_first_name) 261 | 262 | def list_to_str(k): 263 | if not k: 264 | return "N/A" 265 | elif len(k) == 1: 266 | return str(k[0]) 267 | elif MAX_LIST_ELM: 268 | k = k[:int(MAX_LIST_ELM)] 269 | return ' '.join(f'{elem}, ' for elem in k) 270 | else: 271 | return ' '.join(f'{elem}, ' for elem in k) 272 | 273 | def last_online(from_user): 274 | time = "" 275 | if from_user.is_bot: 276 | time += "🤖 Bot :(" 277 | elif from_user.status == enums.UserStatus.RECENTLY: 278 | time += "Recently" 279 | elif from_user.status == enums.UserStatus.LAST_WEEK: 280 | time += "Within the last week" 281 | elif from_user.status == enums.UserStatus.LAST_MONTH: 282 | time += "Within the last month" 283 | elif from_user.status == enums.UserStatus.LONG_AGO: 284 | time += "A long time ago :(" 285 | elif from_user.status == enums.UserStatus.ONLINE: 286 | time += "Currently Online" 287 | elif from_user.status == enums.UserStatus.OFFLINE: 288 | time += from_user.last_online_date.strftime("%a, %d %b %Y, %H:%M:%S") 289 | return time 290 | 291 | 292 | def split_quotes(text: str) -> List: 293 | if not any(text.startswith(char) for char in START_CHAR): 294 | return text.split(None, 1) 295 | counter = 1 # ignore first char -> is some kind of quote 296 | while counter < len(text): 297 | if text[counter] == "\\": 298 | counter += 1 299 | elif text[counter] == text[0] or (text[0] == SMART_OPEN and text[counter] == SMART_CLOSE): 300 | break 301 | counter += 1 302 | else: 303 | return text.split(None, 1) 304 | 305 | # 1 to avoid starting quote, and counter is exclusive so avoids ending 306 | key = remove_escapes(text[1:counter].strip()) 307 | # index will be in range, or `else` would have been executed and returned 308 | rest = text[counter + 1:].strip() 309 | if not key: 310 | key = text[0] + text[0] 311 | return list(filter(None, [key, rest])) 312 | 313 | def gfilterparser(text, keyword): 314 | if "buttonalert" in text: 315 | text = (text.replace("\n", "\\n").replace("\t", "\\t")) 316 | buttons = [] 317 | note_data = "" 318 | prev = 0 319 | i = 0 320 | alerts = [] 321 | for match in BTN_URL_REGEX.finditer(text): 322 | # Check if btnurl is escaped 323 | n_escapes = 0 324 | to_check = match.start(1) - 1 325 | while to_check > 0 and text[to_check] == "\\": 326 | n_escapes += 1 327 | to_check -= 1 328 | 329 | # if even, not escaped -> create button 330 | if n_escapes % 2 == 0: 331 | note_data += text[prev:match.start(1)] 332 | prev = match.end(1) 333 | if match.group(3) == "buttonalert": 334 | # create a thruple with button label, url, and newline status 335 | if bool(match.group(5)) and buttons: 336 | buttons[-1].append(InlineKeyboardButton( 337 | text=match.group(2), 338 | callback_data=f"gfilteralert:{i}:{keyword}" 339 | )) 340 | else: 341 | buttons.append([InlineKeyboardButton( 342 | text=match.group(2), 343 | callback_data=f"gfilteralert:{i}:{keyword}" 344 | )]) 345 | i += 1 346 | alerts.append(match.group(4)) 347 | elif bool(match.group(5)) and buttons: 348 | buttons[-1].append(InlineKeyboardButton( 349 | text=match.group(2), 350 | url=match.group(4).replace(" ", "") 351 | )) 352 | else: 353 | buttons.append([InlineKeyboardButton( 354 | text=match.group(2), 355 | url=match.group(4).replace(" ", "") 356 | )]) 357 | 358 | else: 359 | note_data += text[prev:to_check] 360 | prev = match.start(1) - 1 361 | else: 362 | note_data += text[prev:] 363 | 364 | try: 365 | return note_data, buttons, alerts 366 | except: 367 | return note_data, buttons, None 368 | 369 | def parser(text, keyword): 370 | if "buttonalert" in text: 371 | text = (text.replace("\n", "\\n").replace("\t", "\\t")) 372 | buttons = [] 373 | note_data = "" 374 | prev = 0 375 | i = 0 376 | alerts = [] 377 | for match in BTN_URL_REGEX.finditer(text): 378 | # Check if btnurl is escaped 379 | n_escapes = 0 380 | to_check = match.start(1) - 1 381 | while to_check > 0 and text[to_check] == "\\": 382 | n_escapes += 1 383 | to_check -= 1 384 | 385 | # if even, not escaped -> create button 386 | if n_escapes % 2 == 0: 387 | note_data += text[prev:match.start(1)] 388 | prev = match.end(1) 389 | if match.group(3) == "buttonalert": 390 | # create a thruple with button label, url, and newline status 391 | if bool(match.group(5)) and buttons: 392 | buttons[-1].append(InlineKeyboardButton( 393 | text=match.group(2), 394 | callback_data=f"alertmessage:{i}:{keyword}" 395 | )) 396 | else: 397 | buttons.append([InlineKeyboardButton( 398 | text=match.group(2), 399 | callback_data=f"alertmessage:{i}:{keyword}" 400 | )]) 401 | i += 1 402 | alerts.append(match.group(4)) 403 | elif bool(match.group(5)) and buttons: 404 | buttons[-1].append(InlineKeyboardButton( 405 | text=match.group(2), 406 | url=match.group(4).replace(" ", "") 407 | )) 408 | else: 409 | buttons.append([InlineKeyboardButton( 410 | text=match.group(2), 411 | url=match.group(4).replace(" ", "") 412 | )]) 413 | 414 | else: 415 | note_data += text[prev:to_check] 416 | prev = match.start(1) - 1 417 | else: 418 | note_data += text[prev:] 419 | 420 | try: 421 | return note_data, buttons, alerts 422 | except: 423 | return note_data, buttons, None 424 | 425 | def remove_escapes(text: str) -> str: 426 | res = "" 427 | is_escaped = False 428 | for counter in range(len(text)): 429 | if is_escaped: 430 | res += text[counter] 431 | is_escaped = False 432 | elif text[counter] == "\\": 433 | is_escaped = True 434 | else: 435 | res += text[counter] 436 | return res 437 | 438 | 439 | def humanbytes(size): 440 | if not size: 441 | return "" 442 | power = 2**10 443 | n = 0 444 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'} 445 | while size > power: 446 | size /= power 447 | n += 1 448 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B' 449 | 450 | async def send_all(bot, userid, files, ident): 451 | for file in files: 452 | f_caption = file.caption 453 | title = file.file_name 454 | size = get_size(file.file_size) 455 | if CUSTOM_FILE_CAPTION: 456 | try: 457 | f_caption = CUSTOM_FILE_CAPTION.format(file_name='' if title is None else title, 458 | file_size='' if size is None else size, 459 | file_caption='' if f_caption is None else f_caption) 460 | except Exception as e: 461 | print(e) 462 | f_caption = f_caption 463 | if f_caption is None: 464 | f_caption = f"{title}" 465 | await bot.send_cached_media( 466 | chat_id=userid, 467 | file_id=file.file_id, 468 | caption=f_caption, 469 | protect_content=True if ident == "filep" else False, 470 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('⚔️ 𝖯𝖨𝖱𝖮 𝖴𝖯𝖣𝖠𝖳𝖤𝖲 ⚔️', url="https://t.me/piroxbots") ] ] )) 471 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /plugins/commands.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import random 4 | import asyncio 5 | from Script import script 6 | from pyrogram import Client, filters, enums 7 | from pyrogram.errors import ChatAdminRequired, FloodWait 8 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 9 | from database.ia_filterdb import Media, get_file_details, unpack_new_file_id, get_bad_files 10 | from database.users_chats_db import db 11 | from info import CHANNELS, ADMINS, AUTH_CHANNEL, LOG_CHANNEL, PICS, BATCH_FILE_CAPTION, CUSTOM_FILE_CAPTION, SUPPORT_CHAT, PROTECT_CONTENT, REQST_CHANNEL, SUPPORT_CHAT_ID, MAX_B_TN 12 | from utils import get_settings, get_size, is_subscribed, save_group_settings, temp 13 | from database.connections_mdb import active_connection 14 | import re 15 | import json 16 | import base64 17 | logger = logging.getLogger(__name__) 18 | 19 | BATCH_FILES = {} 20 | 21 | @Client.on_message(filters.command("start") & filters.incoming) 22 | async def start(client, message): 23 | if message.chat.type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 24 | buttons = [[ 25 | InlineKeyboardButton('➕ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖦𝗋𝗈𝗎𝗉 ➕', url=f"http://t.me/{temp.U_NAME}?startgroup=true") 26 | ],[ 27 | InlineKeyboardButton('🛡 𝖮𝗐𝗇𝖾𝗋', callback_data="owner_info"), 28 | InlineKeyboardButton('🧩 𝖲𝗎𝗉𝗉𝗈𝗋𝗍 𝖦𝗋𝗈𝗎𝗉', url=f"https://t.me/{SUPPORT_CHAT}") 29 | ],[ 30 | InlineKeyboardButton('ℹ️ 𝖧𝖾𝗅𝗉', callback_data='help'), 31 | InlineKeyboardButton('😊 𝖠𝖻𝗈𝗎𝗍', callback_data='about') 32 | ],[ 33 | InlineKeyboardButton('🔎 𝖨𝗇𝗅𝗂𝗇𝖾 𝖲𝖾𝖺𝗋𝖼𝗁', switch_inline_query_current_chat='') 34 | ]] 35 | reply_markup = InlineKeyboardMarkup(buttons) 36 | await message.reply(script.START_TXT.format(message.from_user.mention if message.from_user else message.chat.title, temp.U_NAME, temp.B_NAME), reply_markup=reply_markup) 37 | await asyncio.sleep(2) 38 | if not await db.get_chat(message.chat.id): 39 | total=await client.get_chat_members_count(message.chat.id) 40 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, "Unknown")) 41 | await db.add_chat(message.chat.id, message.chat.title) 42 | return 43 | if not await db.is_user_exist(message.from_user.id): 44 | await db.add_user(message.from_user.id, message.from_user.first_name) 45 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_P.format(message.from_user.id, message.from_user.mention)) 46 | if len(message.command) != 2: 47 | buttons = [[ 48 | InlineKeyboardButton('➕ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖦𝗋𝗈𝗎𝗉 ➕', url=f"http://t.me/{temp.U_NAME}?startgroup=true") 49 | ],[ 50 | InlineKeyboardButton('🛡 𝖮𝗐𝗇𝖾𝗋', callback_data="owner_info"), 51 | InlineKeyboardButton('🧩 𝖲𝗎𝗉𝗉𝗈𝗋𝗍 𝖦𝗋𝗈𝗎𝗉', url=f"https://t.me/{SUPPORT_CHAT}") 52 | ],[ 53 | InlineKeyboardButton('ℹ️ 𝖧𝖾𝗅𝗉', callback_data='help'), 54 | InlineKeyboardButton('😊 𝖠𝖻𝗈𝗎𝗍', callback_data='about'), 55 | ],[ 56 | InlineKeyboardButton('🔎 𝖨𝗇𝗅𝗂𝗇𝖾 𝖲𝖾𝖺𝗋𝖼𝗁', switch_inline_query_current_chat='') 57 | ]] 58 | reply_markup = InlineKeyboardMarkup(buttons) 59 | await message.reply_photo( 60 | photo=random.choice(PICS), 61 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME), 62 | reply_markup=reply_markup, 63 | parse_mode=enums.ParseMode.HTML 64 | ) 65 | return 66 | if AUTH_CHANNEL and not await is_subscribed(client, message): 67 | try: 68 | invite_link = await client.create_chat_invite_link(int(AUTH_CHANNEL)) 69 | except ChatAdminRequired: 70 | logger.error("Make sure Bot is admin in Forcesub channel") 71 | return 72 | btn = [ 73 | [ 74 | InlineKeyboardButton( 75 | "🤖 𝖩𝗈𝗂𝗇 𝖴𝗉𝖽𝖺𝗍𝖾𝗌 𝖢𝗁𝖺𝗇𝗇𝖾𝗅 🤖", url=invite_link.invite_link 76 | ) 77 | ] 78 | ] 79 | 80 | if message.command[1] != "subscribe" or message.command[1] != "send_all": 81 | try: 82 | kk, file_id = message.command[1].split("_", 1) 83 | pre = 'checksubp' if kk == 'filep' else 'checksub' 84 | btn.append([InlineKeyboardButton("🔄 𝖳𝗋𝗒 𝖠𝗀𝖺𝗂𝗇 🔄", callback_data=f"{pre}#{file_id}")]) 85 | except (IndexError, ValueError): 86 | btn.append([InlineKeyboardButton("🔄 𝖳𝗋𝗒 𝖠𝗀𝖺𝗂𝗇 🔄", url=f"https://t.me/{temp.U_NAME}?start={message.command[1]}")]) 87 | await client.send_message( 88 | chat_id=message.from_user.id, 89 | text="**Please Join My Updates Channel to use this Bot!**", 90 | reply_markup=InlineKeyboardMarkup(btn), 91 | parse_mode=enums.ParseMode.MARKDOWN 92 | ) 93 | return 94 | if len(message.command) == 2 and message.command[1] in ["subscribe", "error", "okay", "help"]: 95 | buttons = [[ 96 | InlineKeyboardButton('➕ 𝖠𝖽𝖽 𝖬𝖾 𝖳𝗈 𝖸𝗈𝗎𝗋 𝖦𝗋𝗈𝗎𝗉 ➕', url=f"http://t.me/{temp.U_NAME}?startgroup=true") 97 | ],[ 98 | InlineKeyboardButton('🛡 𝖮𝗐𝗇𝖾𝗋', callback_data="owner_info"), 99 | InlineKeyboardButton('🧩 𝖲𝗎𝗉𝗉𝗈𝗋𝗍 𝖦𝗋𝗈𝗎𝗉', url=f"https://t.me/{SUPPORT_CHAT}") 100 | ],[ 101 | InlineKeyboardButton('ℹ️ 𝖧𝖾𝗅𝗉', callback_data='help'), 102 | InlineKeyboardButton('😊 𝖠𝖻𝗈𝗎𝗍', callback_data='about') 103 | ],[ 104 | InlineKeyboardButton('🔎 𝖨𝗇𝗅𝗂𝗇𝖾 𝖲𝖾𝖺𝗋𝖼𝗁', switch_inline_query_current_chat='') 105 | 106 | ]] 107 | reply_markup = InlineKeyboardMarkup(buttons) 108 | await message.reply_photo( 109 | photo=random.choice(PICS), 110 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME), 111 | reply_markup=reply_markup, 112 | parse_mode=enums.ParseMode.HTML 113 | ) 114 | return 115 | data = message.command[1] 116 | try: 117 | pre, file_id = data.split('_', 1) 118 | except: 119 | file_id = data 120 | pre = "" 121 | 122 | if data.startswith("all"): 123 | _, key, pre = data.split("_", 2) 124 | files = temp.FILES_IDS.get(key) 125 | if not files: 126 | return await message.reply('No such file exist.') 127 | 128 | for file in files: 129 | title = file.file_name 130 | size=get_size(file.file_size) 131 | f_caption=file.caption 132 | if CUSTOM_FILE_CAPTION: 133 | try: 134 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 135 | except: 136 | f_caption=f_caption 137 | if f_caption is None: 138 | f_caption = f"{file.file_name}" 139 | await client.send_cached_media( 140 | chat_id=message.from_user.id, 141 | file_id=file.file_id, 142 | caption=f_caption, 143 | protect_content=True if pre == 'filep' else False, 144 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('⚔️ 𝖯𝖨𝖱𝖮 𝖴𝖯𝖣𝖠𝖳𝖤𝖲 ⚔️', url=f"https://t.me/piroxbots") ] ] ), 145 | ) 146 | return 147 | 148 | if data.split("-", 1)[0] == "BATCH": 149 | sts = await message.reply("Please wait...") 150 | file_id = data.split("-", 1)[1] 151 | msgs = BATCH_FILES.get(file_id) 152 | if not msgs: 153 | file = await client.download_media(file_id) 154 | try: 155 | with open(file) as file_data: 156 | msgs=json.loads(file_data.read()) 157 | except: 158 | await sts.edit("FAILED") 159 | return await client.send_message(LOG_CHANNEL, "UNABLE TO OPEN FILE.") 160 | os.remove(file) 161 | BATCH_FILES[file_id] = msgs 162 | for msg in msgs: 163 | title = msg.get("title") 164 | size=get_size(int(msg.get("size", 0))) 165 | f_caption=msg.get("caption", "") 166 | if BATCH_FILE_CAPTION: 167 | try: 168 | f_caption=BATCH_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 169 | except Exception as e: 170 | logger.exception(e) 171 | f_caption=f_caption 172 | if f_caption is None: 173 | f_caption = f"{title}" 174 | try: 175 | await client.send_cached_media( 176 | chat_id=message.from_user.id, 177 | file_id=msg.get("file_id"), 178 | caption=f_caption, 179 | protect_content=msg.get('protect', False), 180 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('⚔️ 𝖯𝖨𝖱𝖮 𝖴𝖯𝖣𝖠𝖳𝖤𝖲 ⚔️', url=f"https://t.me/piroxbots") ] ] ), 181 | 182 | ) 183 | except FloodWait as e: 184 | await asyncio.sleep(e.x) 185 | logger.warning(f"Floodwait of {e.x} sec.") 186 | await client.send_cached_media( 187 | chat_id=message.from_user.id, 188 | file_id=msg.get("file_id"), 189 | caption=f_caption, 190 | protect_content=msg.get('protect', False), 191 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('⚔️ 𝖯𝖨𝖱𝖮 𝖴𝖯𝖣𝖠𝖳𝖤𝖲 ⚔️', url=f"https://t.me/piroxbots") ] ] ), 192 | ) 193 | except Exception as e: 194 | logger.warning(e, exc_info=True) 195 | continue 196 | await asyncio.sleep(1) 197 | await sts.delete() 198 | return 199 | elif data.split("-", 1)[0] == "DSTORE": 200 | sts = await message.reply("Please wait...") 201 | b_string = data.split("-", 1)[1] 202 | decoded = (base64.urlsafe_b64decode(b_string + "=" * (-len(b_string) % 4))).decode("ascii") 203 | try: 204 | f_msg_id, l_msg_id, f_chat_id, protect = decoded.split("_", 3) 205 | except: 206 | f_msg_id, l_msg_id, f_chat_id = decoded.split("_", 2) 207 | protect = "/pbatch" if PROTECT_CONTENT else "batch" 208 | diff = int(l_msg_id) - int(f_msg_id) 209 | async for msg in client.iter_messages(int(f_chat_id), int(l_msg_id), int(f_msg_id)): 210 | if msg.media: 211 | media = getattr(msg, msg.media.value) 212 | if BATCH_FILE_CAPTION: 213 | try: 214 | f_caption=BATCH_FILE_CAPTION.format(file_name=getattr(media, 'file_name', ''), file_size=getattr(media, 'file_size', ''), file_caption=getattr(msg, 'caption', '')) 215 | except Exception as e: 216 | logger.exception(e) 217 | f_caption = getattr(msg, 'caption', '') 218 | else: 219 | media = getattr(msg, msg.media.value) 220 | file_name = getattr(media, 'file_name', '') 221 | f_caption = getattr(msg, 'caption', file_name) 222 | try: 223 | await msg.copy(message.chat.id, caption=f_caption, protect_content=True if protect == "/pbatch" else False) 224 | except FloodWait as e: 225 | await asyncio.sleep(e.x) 226 | await msg.copy(message.chat.id, caption=f_caption, protect_content=True if protect == "/pbatch" else False) 227 | except Exception as e: 228 | logger.exception(e) 229 | continue 230 | elif msg.empty: 231 | continue 232 | else: 233 | try: 234 | await msg.copy(message.chat.id, protect_content=True if protect == "/pbatch" else False) 235 | except FloodWait as e: 236 | await asyncio.sleep(e.x) 237 | await msg.copy(message.chat.id, protect_content=True if protect == "/pbatch" else False) 238 | except Exception as e: 239 | logger.exception(e) 240 | continue 241 | await asyncio.sleep(1) 242 | return await sts.delete() 243 | 244 | 245 | files_ = await get_file_details(file_id) 246 | if not files_: 247 | pre, file_id = ((base64.urlsafe_b64decode(data + "=" * (-len(data) % 4))).decode("ascii")).split("_", 1) 248 | try: 249 | msg = await client.send_cached_media( 250 | chat_id=message.from_user.id, 251 | file_id=file_id, 252 | protect_content=True if pre == 'filep' else False, 253 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('⚔️ 𝖯𝖨𝖱𝖮 𝖴𝖯𝖣𝖠𝖳𝖤𝖲 ⚔️', url="https://t.me/piroxbots") ] ] ), 254 | ) 255 | filetype = msg.media 256 | file = getattr(msg, filetype.value) 257 | title = file.file_name 258 | size=get_size(file.file_size) 259 | f_caption = f"{title}" 260 | if CUSTOM_FILE_CAPTION: 261 | try: 262 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='') 263 | except: 264 | return 265 | await msg.edit_caption(f_caption) 266 | return 267 | except: 268 | pass 269 | return await message.reply('No such file exist.') 270 | files = files_[0] 271 | title = files.file_name 272 | size=get_size(files.file_size) 273 | f_caption=files.caption 274 | if CUSTOM_FILE_CAPTION: 275 | try: 276 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 277 | except Exception as e: 278 | logger.exception(e) 279 | f_caption=f_caption 280 | if f_caption is None: 281 | f_caption = f"{files.file_name}" 282 | await client.send_cached_media( 283 | chat_id=message.from_user.id, 284 | file_id=file_id, 285 | caption=f_caption, 286 | protect_content=True if pre == 'filep' else False, 287 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('⚔️ 𝖯𝖨𝖱𝖮 𝖴𝖯𝖣𝖠𝖳𝖤𝖲 ⚔️', url="https://t.me/piroxbots") ] ] ), 288 | ) 289 | 290 | 291 | @Client.on_message(filters.command('channel') & filters.user(ADMINS)) 292 | async def channel_info(bot, message): 293 | 294 | """Send basic information of channel""" 295 | if isinstance(CHANNELS, (int, str)): 296 | channels = [CHANNELS] 297 | elif isinstance(CHANNELS, list): 298 | channels = CHANNELS 299 | else: 300 | raise ValueError("Unexpected type of CHANNELS") 301 | 302 | text = '📑 **Indexed channels/groups**\n' 303 | for channel in channels: 304 | chat = await bot.get_chat(channel) 305 | if chat.username: 306 | text += '\n@' + chat.username 307 | else: 308 | text += '\n' + chat.title or chat.first_name 309 | 310 | text += f'\n\n**Total:** {len(CHANNELS)}' 311 | 312 | if len(text) < 4096: 313 | await message.reply(text) 314 | else: 315 | file = 'Indexed channels.txt' 316 | with open(file, 'w') as f: 317 | f.write(text) 318 | await message.reply_document(file) 319 | os.remove(file) 320 | 321 | 322 | @Client.on_message(filters.command('logs') & filters.user(ADMINS)) 323 | async def log_file(bot, message): 324 | """Send log file""" 325 | try: 326 | await message.reply_document('Logs.txt') 327 | except Exception as e: 328 | await message.reply(str(e)) 329 | 330 | @Client.on_message(filters.command('delete') & filters.user(ADMINS)) 331 | async def delete(bot, message): 332 | """Delete file from database""" 333 | reply = message.reply_to_message 334 | if reply and reply.media: 335 | msg = await message.reply("Processing...⏳", quote=True) 336 | else: 337 | await message.reply('Reply to file with /delete which you want to delete', quote=True) 338 | return 339 | 340 | for file_type in ("document", "video", "audio"): 341 | media = getattr(reply, file_type, None) 342 | if media is not None: 343 | break 344 | else: 345 | await msg.edit('This is not supported file format') 346 | return 347 | 348 | file_id, file_ref = unpack_new_file_id(media.file_id) 349 | 350 | result = await Media.collection.delete_one({ 351 | '_id': file_id, 352 | }) 353 | if result.deleted_count: 354 | await msg.edit('File is successfully deleted from database') 355 | else: 356 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 357 | result = await Media.collection.delete_many({ 358 | 'file_name': file_name, 359 | 'file_size': media.file_size, 360 | 'mime_type': media.mime_type 361 | }) 362 | if result.deleted_count: 363 | await msg.edit('File is successfully deleted from database') 364 | else: 365 | result = await Media.collection.delete_many({ 366 | 'file_name': media.file_name, 367 | 'file_size': media.file_size, 368 | 'mime_type': media.mime_type 369 | }) 370 | if result.deleted_count: 371 | await msg.edit('File is successfully deleted from database') 372 | else: 373 | await msg.edit('File not found in database') 374 | 375 | 376 | @Client.on_message(filters.command('deleteall') & filters.user(ADMINS)) 377 | async def delete_all_index(bot, message): 378 | await message.reply_text( 379 | 'This will delete all indexed files.\nDo you want to continue??', 380 | reply_markup=InlineKeyboardMarkup( 381 | [ 382 | [ 383 | InlineKeyboardButton( 384 | text="YES", callback_data="autofilter_delete" 385 | ) 386 | ], 387 | [ 388 | InlineKeyboardButton( 389 | text="CANCEL", callback_data="close_data" 390 | ) 391 | ], 392 | ] 393 | ), 394 | quote=True, 395 | ) 396 | 397 | 398 | @Client.on_callback_query(filters.regex(r'^autofilter_delete')) 399 | async def delete_all_index_confirm(bot, message): 400 | await Media.collection.drop() 401 | await message.answer('Piracy Is Crime') 402 | await message.message.edit('Succesfully Deleted All The Indexed Files.') 403 | 404 | 405 | @Client.on_message(filters.command('settings')) 406 | async def settings(client, message): 407 | userid = message.from_user.id if message.from_user else None 408 | if not userid: 409 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 410 | chat_type = message.chat.type 411 | 412 | if chat_type == enums.ChatType.PRIVATE: 413 | grpid = await active_connection(str(userid)) 414 | if grpid is not None: 415 | grp_id = grpid 416 | try: 417 | chat = await client.get_chat(grpid) 418 | title = chat.title 419 | except: 420 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 421 | return 422 | else: 423 | await message.reply_text("I'm not connected to any groups!", quote=True) 424 | return 425 | 426 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 427 | grp_id = message.chat.id 428 | title = message.chat.title 429 | 430 | else: 431 | return 432 | 433 | st = await client.get_chat_member(grp_id, userid) 434 | if ( 435 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 436 | and st.status != enums.ChatMemberStatus.OWNER 437 | and str(userid) not in ADMINS 438 | ): 439 | return 440 | 441 | settings = await get_settings(grp_id) 442 | 443 | try: 444 | if settings['max_btn']: 445 | settings = await get_settings(grp_id) 446 | except KeyError: 447 | await save_group_settings(grp_id, 'max_btn', False) 448 | settings = await get_settings(grp_id) 449 | 450 | if settings is not None: 451 | buttons = [ 452 | [ 453 | InlineKeyboardButton( 454 | '𝖥𝗂𝗅𝗍𝖾𝗋 𝖡𝗎𝗍𝗍𝗈𝗇', 455 | callback_data=f'setgs#button#{settings["button"]}#{grp_id}', 456 | ), 457 | InlineKeyboardButton( 458 | '𝖲𝗂𝗇𝗀𝗅𝖾 𝖡𝗎𝗍𝗍𝗈𝗇' if settings["button"] else '𝖣𝗈𝗎𝖻𝗅𝖾', 459 | callback_data=f'setgs#button#{settings["button"]}#{grp_id}', 460 | ), 461 | ], 462 | [ 463 | InlineKeyboardButton( 464 | '𝖥𝗂𝗅𝖾 𝖲𝖾𝗇𝖽 𝖬𝗈𝖽𝖾', 465 | callback_data=f'setgs#botpm#{settings["botpm"]}#{grp_id}', 466 | ), 467 | InlineKeyboardButton( 468 | '𝖬𝖺𝗇𝗎𝖺𝗅 𝖲𝗍𝖺𝗋𝗍' if settings["botpm"] else '𝖠𝗎𝗍𝗈 𝖲𝖾𝗇𝖽', 469 | callback_data=f'setgs#botpm#{settings["botpm"]}#{grp_id}', 470 | ), 471 | ], 472 | [ 473 | InlineKeyboardButton( 474 | '𝖯𝗋𝗈𝗍𝖾𝖼𝗍 𝖢𝗈𝗇𝗍𝖾𝗇𝗍', 475 | callback_data=f'setgs#file_secure#{settings["file_secure"]}#{grp_id}', 476 | ), 477 | InlineKeyboardButton( 478 | '✅ 𝖮𝗇' if settings["file_secure"] else '❌ 𝖮𝖿𝖿', 479 | callback_data=f'setgs#file_secure#{settings["file_secure"]}#{grp_id}', 480 | ), 481 | ], 482 | [ 483 | InlineKeyboardButton( 484 | '𝖨𝖬𝖣𝖻', 485 | callback_data=f'setgs#imdb#{settings["imdb"]}#{grp_id}', 486 | ), 487 | InlineKeyboardButton( 488 | '✅ 𝖮𝗇' if settings["imdb"] else '❌ 𝖮𝖿𝖿', 489 | callback_data=f'setgs#imdb#{settings["imdb"]}#{grp_id}', 490 | ), 491 | ], 492 | [ 493 | InlineKeyboardButton( 494 | '𝖲𝗉𝖾𝗅𝗅 𝖢𝗁𝖾𝖼𝗄', 495 | callback_data=f'setgs#spell_check#{settings["spell_check"]}#{grp_id}', 496 | ), 497 | InlineKeyboardButton( 498 | '✅ 𝖮𝗇' if settings["spell_check"] else '❌ 𝖮𝖿𝖿', 499 | callback_data=f'setgs#spell_check#{settings["spell_check"]}#{grp_id}', 500 | ), 501 | ], 502 | [ 503 | InlineKeyboardButton( 504 | '𝖶𝖾𝗅𝖼𝗈𝗆𝖾 𝖬𝖾𝗌𝗌𝖺𝗀𝖾', 505 | callback_data=f'setgs#welcome#{settings["welcome"]}#{grp_id}', 506 | ), 507 | InlineKeyboardButton( 508 | '✅ 𝖮𝗇' if settings["welcome"] else '❌ 𝖮𝖿𝖿', 509 | callback_data=f'setgs#welcome#{settings["welcome"]}#{grp_id}', 510 | ), 511 | ], 512 | [ 513 | InlineKeyboardButton( 514 | '𝖠𝗎𝗍𝗈 𝖣𝖾𝗅𝖾𝗍𝖾', 515 | callback_data=f'setgs#auto_delete#{settings["auto_delete"]}#{grp_id}', 516 | ), 517 | InlineKeyboardButton( 518 | '5 𝖬𝗂𝗇' if settings["auto_delete"] else '❌ 𝖮𝖿𝖿', 519 | callback_data=f'setgs#auto_delete#{settings["auto_delete"]}#{grp_id}', 520 | ), 521 | ], 522 | [ 523 | InlineKeyboardButton( 524 | '𝖠𝗎𝗍𝗈-𝖥𝗂𝗅𝗍𝖾𝗋', 525 | callback_data=f'setgs#auto_ffilter#{settings["auto_ffilter"]}#{grp_id}', 526 | ), 527 | InlineKeyboardButton( 528 | '✅ 𝖮𝗇' if settings["auto_ffilter"] else '❌ 𝖮𝖿𝖿', 529 | callback_data=f'setgs#auto_ffilter#{settings["auto_ffilter"]}#{grp_id}', 530 | ), 531 | ], 532 | [ 533 | InlineKeyboardButton( 534 | '𝖬𝖺𝗑 𝖡𝗎𝗍𝗍𝗈𝗇𝗌', 535 | callback_data=f'setgs#max_btn#{settings["max_btn"]}#{grp_id}', 536 | ), 537 | InlineKeyboardButton( 538 | '10' if settings["max_btn"] else f'{MAX_B_TN}', 539 | callback_data=f'setgs#max_btn#{settings["max_btn"]}#{grp_id}', 540 | ), 541 | ], 542 | ] 543 | 544 | btn = [[ 545 | InlineKeyboardButton("⬇ 𝖮𝗉𝖾𝗇 𝖧𝖾𝗋𝖾 ⬇", callback_data=f"opnsetgrp#{grp_id}"), 546 | InlineKeyboardButton("➡ 𝖮𝗉𝖾𝗇 𝗂𝗇 𝖯𝖬 ➡", callback_data=f"opnsetpm#{grp_id}") 547 | ]] 548 | 549 | reply_markup = InlineKeyboardMarkup(buttons) 550 | if chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 551 | await message.reply_text( 552 | text="𝖣𝗈 𝖸𝗈𝗎 𝖶𝖺𝗇𝗍 𝖳𝗈 𝖮𝗉𝖾𝗇 𝖲𝖾𝗍𝗍𝗂𝗇𝗀𝗌 𝖧𝖾𝗋𝖾 ?", 553 | reply_markup=InlineKeyboardMarkup(btn), 554 | disable_web_page_preview=True, 555 | parse_mode=enums.ParseMode.HTML, 556 | reply_to_message_id=message.id 557 | ) 558 | else: 559 | await message.reply_text( 560 | text=f"𝖢𝗁𝖺𝗇𝗀𝖾 𝖸𝗈𝗎𝗋 𝖲𝖾𝗍𝗍𝗂𝗇𝗀𝗌 𝖥𝗈𝗋 {title} 𝖠𝗌 𝖸𝗈𝗎𝗋 𝖶𝗂𝗌𝗁", 561 | reply_markup=reply_markup, 562 | disable_web_page_preview=True, 563 | parse_mode=enums.ParseMode.HTML, 564 | reply_to_message_id=message.id 565 | ) 566 | 567 | @Client.on_message(filters.command("send") & filters.user(ADMINS)) 568 | async def send_msg(bot, message): 569 | if message.reply_to_message: 570 | target_id = message.text 571 | command = ["/send"] 572 | out = "Users Saved In DB Are:\n\n" 573 | for cmd in command: 574 | if cmd in target_id: 575 | target_id = target_id.replace(cmd, "") 576 | success = False 577 | try: 578 | user = await bot.get_users(target_id) 579 | users = await db.get_all_users() 580 | async for usr in users: 581 | out += f"{usr['id']}" 582 | out += '\n' 583 | if str(user.id) in str(out): 584 | await message.reply_to_message.copy(int(user.id)) 585 | success = True 586 | else: 587 | success = False 588 | if success: 589 | await message.reply_text(f"Your message has been successfully send to {user.mention}.") 590 | else: 591 | await message.reply_text("This user didn't started this bot yet !") 592 | except Exception as e: 593 | await message.reply_text(f"Error: {e}") 594 | else: 595 | await message.reply_text("Use this command as a reply to any message using the target chat id. For eg: /send userid") 596 | 597 | @Client.on_message(filters.command('set_template')) 598 | async def save_template(client, message): 599 | sts = await message.reply("Checking template") 600 | userid = message.from_user.id if message.from_user else None 601 | if not userid: 602 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 603 | chat_type = message.chat.type 604 | 605 | if chat_type == enums.ChatType.PRIVATE: 606 | grpid = await active_connection(str(userid)) 607 | if grpid is not None: 608 | grp_id = grpid 609 | try: 610 | chat = await client.get_chat(grpid) 611 | title = chat.title 612 | except: 613 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 614 | return 615 | else: 616 | await message.reply_text("I'm not connected to any groups!", quote=True) 617 | return 618 | 619 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 620 | grp_id = message.chat.id 621 | title = message.chat.title 622 | 623 | else: 624 | return 625 | 626 | st = await client.get_chat_member(grp_id, userid) 627 | if ( 628 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 629 | and st.status != enums.ChatMemberStatus.OWNER 630 | and str(userid) not in ADMINS 631 | ): 632 | return 633 | 634 | if len(message.command) < 2: 635 | return await sts.edit("No Input!!") 636 | template = message.text.split(" ", 1)[1] 637 | await save_group_settings(grp_id, 'template', template) 638 | await sts.edit(f"Successfully changed template for {title} to\n\n{template}") 639 | 640 | 641 | @Client.on_message((filters.command(["request", "Request"]) | filters.regex("#request") | filters.regex("#Request")) & filters.group) 642 | async def requests(bot, message): 643 | if REQST_CHANNEL is None or SUPPORT_CHAT_ID is None: return # Must add REQST_CHANNEL and SUPPORT_CHAT_ID to use this feature 644 | if message.reply_to_message and SUPPORT_CHAT_ID == message.chat.id: 645 | chat_id = message.chat.id 646 | reporter = str(message.from_user.id) 647 | mention = message.from_user.mention 648 | success = True 649 | content = message.reply_to_message.text 650 | try: 651 | if REQST_CHANNEL is not None: 652 | btn = [[ 653 | InlineKeyboardButton('📥 𝖵𝗂𝖾𝗐 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 📥', url=f"{message.reply_to_message.link}"), 654 | InlineKeyboardButton('📝 𝖲𝗁𝗈𝗐 𝖮𝗉𝗍𝗂𝗈𝗇𝗌 📝', callback_data=f'show_option#{reporter}') 655 | ]] 656 | reported_post = await bot.send_message(chat_id=REQST_CHANNEL, text=f"𝖱𝖾𝗉𝗈𝗋𝗍𝖾𝗋 : {mention} ({reporter})\n\n𝖬𝖾𝗌𝗌𝖺𝗀𝖾 : {content}", reply_markup=InlineKeyboardMarkup(btn)) 657 | success = True 658 | elif len(content) >= 3: 659 | for admin in ADMINS: 660 | btn = [[ 661 | InlineKeyboardButton('📥 𝖵𝗂𝖾𝗐 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 📥', url=f"{message.reply_to_message.link}"), 662 | InlineKeyboardButton('📝 𝖲𝗁𝗈𝗐 𝖮𝗉𝗍𝗂𝗈𝗇𝗌 📝', callback_data=f'show_option#{reporter}') 663 | ]] 664 | reported_post = await bot.send_message(chat_id=admin, text=f"𝖱𝖾𝗉𝗈𝗋𝗍𝖾𝗋 : {mention} ({reporter})\n\n𝖬𝖾𝗌𝗌𝖺𝗀𝖾 : {content}", reply_markup=InlineKeyboardMarkup(btn)) 665 | success = True 666 | else: 667 | if len(content) < 3: 668 | await message.reply_text("You must type about your request [Minimum 3 Characters]. Requests can't be empty.") 669 | if len(content) < 3: 670 | success = False 671 | except Exception as e: 672 | await message.reply_text(f"Error: {e}") 673 | pass 674 | 675 | elif SUPPORT_CHAT_ID == message.chat.id: 676 | chat_id = message.chat.id 677 | reporter = str(message.from_user.id) 678 | mention = message.from_user.mention 679 | success = True 680 | content = message.text 681 | keywords = ["#request", "/request", "#Request", "/Request"] 682 | for keyword in keywords: 683 | if keyword in content: 684 | content = content.replace(keyword, "") 685 | try: 686 | if REQST_CHANNEL is not None and len(content) >= 3: 687 | btn = [[ 688 | InlineKeyboardButton('📥 𝖵𝗂𝖾𝗐 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 📥', url=f"{message.link}"), 689 | InlineKeyboardButton('📝 𝖲𝗁𝗈𝗐 𝖮𝗉𝗍𝗂𝗈𝗇𝗌 📝', callback_data=f'show_option#{reporter}') 690 | ]] 691 | reported_post = await bot.send_message(chat_id=REQST_CHANNEL, text=f"𝖱𝖾𝗉𝗈𝗋𝗍𝖾𝗋 : {mention} ({reporter})\n\n𝖬𝖾𝗌𝗌𝖺𝗀𝖾 : {content}", reply_markup=InlineKeyboardMarkup(btn)) 692 | success = True 693 | elif len(content) >= 3: 694 | for admin in ADMINS: 695 | btn = [[ 696 | InlineKeyboardButton('📥 𝖵𝗂𝖾𝗐 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 📥', url=f"{message.link}"), 697 | InlineKeyboardButton('📝 𝖲𝗁𝗈𝗐 𝖮𝗉𝗍𝗂𝗈𝗇𝗌 📝', callback_data=f'show_option#{reporter}') 698 | ]] 699 | reported_post = await bot.send_message(chat_id=admin, text=f"𝖱𝖾𝗉𝗈𝗋𝗍𝖾𝗋 : {mention} ({reporter})\n\n𝖬𝖾𝗌𝗌𝖺𝗀𝖾 : {content}", reply_markup=InlineKeyboardMarkup(btn)) 700 | success = True 701 | else: 702 | if len(content) < 3: 703 | await message.reply_text("You must type about your request [Minimum 3 Characters]. Requests can't be empty.") 704 | if len(content) < 3: 705 | success = False 706 | except Exception as e: 707 | await message.reply_text(f"Error: {e}") 708 | pass 709 | 710 | else: 711 | success = False 712 | 713 | if success: 714 | btn = [[ 715 | InlineKeyboardButton('📥 𝖵𝗂𝖾𝗐 𝖱𝖾𝗊𝗎𝖾𝗌𝗍 📥', url=f"{reported_post.link}") 716 | ]] 717 | await message.reply_text("Your request has been added! Please wait for some time.", reply_markup=InlineKeyboardMarkup(btn)) 718 | 719 | @Client.on_message(filters.command("usend") & filters.user(ADMINS)) 720 | async def send_msg(bot, message): 721 | if message.reply_to_message: 722 | target_id = message.text.split(" ", 1)[1] 723 | out = "Users Saved In DB Are:\n\n" 724 | success = False 725 | try: 726 | user = await bot.get_users(target_id) 727 | users = await db.get_all_users() 728 | async for usr in users: 729 | out += f"{usr['id']}" 730 | out += '\n' 731 | if str(user.id) in str(out): 732 | await message.reply_to_message.copy(int(user.id)) 733 | success = True 734 | else: 735 | success = False 736 | if success: 737 | await message.reply_text(f"𝖸𝗈𝗎𝗋 𝖬𝖾𝗌𝗌𝖺𝗀𝖾 𝖧𝖺𝗌 𝖲𝗎𝖼𝖼𝖾𝗌𝗌𝖿𝗎𝗅𝗅𝗒 𝖲𝖾𝗇𝗍 𝖳𝗈 {user.mention}.") 738 | else: 739 | await message.reply_text("An Error Occured !") 740 | except Exception as e: 741 | await message.reply_text(f"Error :- {e}") 742 | else: 743 | await message.reply_text("Error𝖢𝗈𝗆𝗆𝖺𝗇𝖽 𝖨𝗇𝖼𝗈𝗆𝗉𝗅𝖾𝗍𝖾 !") 744 | 745 | @Client.on_message(filters.command("send") & filters.user(ADMINS)) 746 | async def send_msg(bot, message): 747 | if message.reply_to_message: 748 | target_id = message.text.split(" ", 1)[1] 749 | out = "Users Saved In DB Are:\n\n" 750 | success = False 751 | try: 752 | user = await bot.get_users(target_id) 753 | users = await db.get_all_users() 754 | async for usr in users: 755 | out += f"{usr['id']}" 756 | out += '\n' 757 | if str(user.id) in str(out): 758 | await message.reply_to_message.copy(int(user.id)) 759 | success = True 760 | else: 761 | success = False 762 | if success: 763 | await message.reply_text(f"Your message has been successfully send to {user.mention}.") 764 | else: 765 | await message.reply_text("This user didn't started this bot yet !") 766 | except Exception as e: 767 | await message.reply_text(f"Error: {e}") 768 | else: 769 | await message.reply_text("Use this command as a reply to any message using the target chat id. For eg: /send userid") 770 | 771 | @Client.on_message(filters.command("gsend") & filters.user(ADMINS)) 772 | async def send_chatmsg(bot, message): 773 | if message.reply_to_message: 774 | target_id = message.text.split(" ", 1)[1] 775 | out = "Chats Saved In DB Are:\n\n" 776 | success = False 777 | try: 778 | chat = await bot.get_chat(target_id) 779 | chats = await db.get_all_chats() 780 | async for cht in chats: 781 | out += f"{cht['id']}" 782 | out += '\n' 783 | if str(chat.id) in str(out): 784 | await message.reply_to_message.copy(int(chat.id)) 785 | success = True 786 | else: 787 | success = False 788 | if success: 789 | await message.reply_text(f"Your message has been successfully send to {chat.id}.") 790 | else: 791 | await message.reply_text("An Error Occured !") 792 | except Exception as e: 793 | await message.reply_text(f"Error :- {e}") 794 | else: 795 | await message.reply_text("Error𝖢𝗈𝗆𝗆𝖺𝗇𝖽 𝖨𝗇𝖼𝗈𝗆𝗉𝗅𝖾𝗍𝖾 !") 796 | 797 | @Client.on_message(filters.command("deletefiles") & filters.user(ADMINS)) 798 | async def deletemultiplefiles(bot, message): 799 | chat_type = message.chat.type 800 | if chat_type != enums.ChatType.PRIVATE: 801 | return await message.reply_text(f"Hey {message.from_user.mention}, This command won't work in groups. It only works on my PM !") 802 | else: 803 | pass 804 | try: 805 | keyword = message.text.split(" ", 1)[1] 806 | except: 807 | return await message.reply_text(f"Hey {message.from_user.mention}, Give me a keyword along with the command to delete files.") 808 | k = await bot.send_message(chat_id=message.chat.id, text=f"Fetching Files for your query {keyword} on DB... Please wait...") 809 | files, total = await get_bad_files(keyword) 810 | await k.edit_text(f"Found {total} files for your query {keyword} !\n\nFile deletion process will start in 5 seconds !") 811 | await asyncio.sleep(5) 812 | deleted = 0 813 | for file in files: 814 | await k.edit_text(f"Process started for deleting files from DB. Successfully deleted {str(deleted)} files from DB for your query {keyword} !\n\nPlease wait...") 815 | file_ids = file.file_id 816 | file_name = file.file_name 817 | result = await Media.collection.delete_one({ 818 | '_id': file_ids, 819 | }) 820 | if result.deleted_count: 821 | logger.info(f'File Found for your query {keyword}! Successfully deleted {file_name} from database.') 822 | deleted += 1 823 | await k.edit_text(text=f"Process Completed for file deletion !\n\nSuccessfully deleted {str(deleted)} files from database for your query {keyword}.") 824 | --------------------------------------------------------------------------------