├── assets ├── Test ├── AJAX.png ├── logo.jpg ├── logoo.jpg └── Picsart_22-02-20_13-02-59-464.jpg ├── plugins ├── modules │ ├── @ │ └── carbon.py ├── channel.py ├── function.py ├── broadcast.py ├── banned.py ├── inline.py ├── connection.py ├── misc.py ├── index.py ├── filters.py ├── commands.py ├── p_ttishow.py └── pm_filter.py ├── runtime.txt ├── Procfile ├── heroku.yml ├── Dockerfile ├── start.sh ├── logging.conf ├── sample_info.py ├── requirements.txt ├── bot.py ├── .gitignore ├── database ├── filters_mdb.py ├── connections_mdb.py ├── users_chats_db.py └── ia_filterdb.py ├── info.py ├── README.md ├── app.json ├── Script.py ├── utils.py └── LICENSE /assets/Test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /plugins/modules/@: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.8.7 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 bot.py -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile -------------------------------------------------------------------------------- /assets/AJAX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/AJAX.png -------------------------------------------------------------------------------- /assets/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/logo.jpg -------------------------------------------------------------------------------- /assets/logoo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/logoo.jpg -------------------------------------------------------------------------------- /assets/Picsart_22-02-20_13-02-59-464.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CyniteOfficial/Auto-Filter/HEAD/assets/Picsart_22-02-20_13-02-59-464.jpg -------------------------------------------------------------------------------- /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 | RUN mkdir /EvaMaria 10 | WORKDIR /EvaMaria 11 | COPY start.sh /start.sh 12 | CMD ["/bin/bash", "/start.sh"] 13 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | if [ -z $UPSTREAM_REPO ] 2 | then 3 | echo "Cloning main Repository" 4 | git clone https://github.com/Aadhi000/Ajax.git /Ajax 5 | else 6 | echo "Cloning Custom Repo from $UPSTREAM_REPO " 7 | git clone $UPSTREAM_REPO /Ajax 8 | fi 9 | cd /Ajax 10 | pip3 install -U -r requirements.txt 11 | echo "Starting ᗩᒍᗩ᙭....🔥" 12 | python3 bot.py 13 | -------------------------------------------------------------------------------- /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 | filters.audio 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", "audio"): 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) -------------------------------------------------------------------------------- /plugins/function.py: -------------------------------------------------------------------------------- 1 | from asyncio import gather 2 | from datetime import datetime, timedelta 3 | from io import BytesIO 4 | from math import atan2, cos, radians, sin, sqrt 5 | from os import execvp 6 | from random import randint 7 | from re import findall 8 | from re import sub as re_sub 9 | from sys import executable 10 | from aiohttp import ClientSession 11 | 12 | import aiofiles 13 | from PIL import Image 14 | from pyrogram.types import Message 15 | 16 | aiohttpsession = ClientSession() 17 | 18 | async def make_carbon(code): 19 | url = "https://carbonara.vercel.app/api/cook" 20 | async with aiohttpsession.post(url, json={"code": code}) as resp: 21 | image = BytesIO(await resp.read()) 22 | image.name = "carbon.png" 23 | return image 24 | -------------------------------------------------------------------------------- /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=('TelegramBot.log','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 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/subinps/pyrogram@inline-m 2 | tgcrypto 3 | pymongo[srv]==3.11.4 4 | motor==2.4.0 5 | marshmallow==3.12.2 6 | python-telegram-bot==11.1.0 7 | umongo==3.0.0 8 | requests 9 | bs4 10 | Pyromod 11 | imdbpy==2021.4.18 12 | youtube-dl 13 | youtube_search 14 | requests 15 | googletrans==3.1.0a0 16 | telegraph 17 | beautifulsoup4 18 | aiohttp==3.7.4 19 | gTTS 20 | googletrans==3.1.0a0 21 | NumPy 22 | glitch_this 23 | opencv-python-headless 24 | youtube-search-python==1.4.6 25 | yt-dlp 26 | pypng 27 | Pillow 28 | wget 29 | aiofiles 30 | psutil 31 | wheel 32 | humanize 33 | ytthumb 34 | pypdf2 35 | PyPDF2 36 | pyshorteners 37 | ffmpeg-python 38 | TgCrypto 39 | py-tgcalls 40 | python-dotenv 41 | youtube_search_python 42 | requests 43 | aiohttp 44 | aiofiles 45 | asyncio 46 | youtube_search 47 | search_engine_parser 48 | ffmpeg-python 49 | ffmpeg 50 | Pillow 51 | ujson 52 | -------------------------------------------------------------------------------- /plugins/modules/carbon.py: -------------------------------------------------------------------------------- 1 | from pyrogram import filters 2 | from aiohttp import ClientSession 3 | from pyrogram import Client as bot 4 | from plugins.function import make_carbon 5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 6 | aiohttpsession = ClientSession() 7 | 8 | C = "**𝙼𝙰𝙳𝙴 𝙱𝚈 [AYUSH](https://t.me/Aks_support01_bot)**" 9 | F = InlineKeyboardMarkup( 10 | [[ 11 | InlineKeyboardButton("𝚄𝙿𝙳𝙰𝚃𝙴𝚉 𝙲𝙷𝙰𝙽𝙽𝙴𝙻", url="https://t.me/Imdb_updates") 12 | ]] 13 | ) 14 | 15 | 16 | 17 | 18 | @bot.on_message(filters.command("carbon")) 19 | async def carbon_func(_, message): 20 | if not message.reply_to_message: 21 | return await message.reply_text( 22 | "**𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰𝙽𝚈 𝚃𝙴𝚇𝚃 𝙼𝙴𝚂𝚂𝙰𝙶𝙴 𝚃𝙾 𝙼𝙰𝙺𝙴 𝙲𝙰𝚁𝙱𝙾𝙽.**" 23 | ) 24 | if not message.reply_to_message.text: 25 | return await message.reply_text( 26 | "**𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰𝙽𝚈 𝚃𝙴𝚇𝚃 𝙼𝙴𝚂𝚂𝙰𝙶𝙴 𝚃𝙾 𝙼𝙰𝙺𝙴 𝙲𝙰𝚁𝙱𝙾𝙽.**" 27 | ) 28 | user_id = message.from_user.id 29 | m = await message.reply_text("**𝙲𝚁𝙴𝙰𝚃𝙸𝙽𝙶 𝙲𝙰𝚁𝙱𝙾𝙽...**") 30 | carbon = await make_carbon(message.reply_to_message.text) 31 | await m.edit("**𝚄𝙿𝙻𝙾𝙰𝙳𝙸𝙽𝙶 𝙲𝙰𝚁𝙱𝙾𝙽...**") 32 | await message.reply_photo( 33 | photo=carbon, 34 | caption=C, 35 | reply_markup=F) 36 | await m.delete() 37 | carbon.close() 38 | -------------------------------------------------------------------------------- /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 15 | from utils import temp 16 | 17 | class Bot(Client): 18 | 19 | def __init__(self): 20 | super().__init__( 21 | session_name=SESSION, 22 | api_id=API_ID, 23 | api_hash=API_HASH, 24 | bot_token=BOT_TOKEN, 25 | workers=50, 26 | plugins={"root": "plugins"}, 27 | sleep_threshold=5, 28 | ) 29 | 30 | async def start(self): 31 | b_users, b_chats = await db.get_banned() 32 | temp.BANNED_USERS = b_users 33 | temp.BANNED_CHATS = b_chats 34 | await super().start() 35 | await Media.ensure_indexes() 36 | me = await self.get_me() 37 | temp.ME = me.id 38 | temp.U_NAME = me.username 39 | temp.B_NAME = me.first_name 40 | self.username = '@' + me.username 41 | logging.info(f"{me.first_name} with for Pyrogram v{__version__} (Layer {layer}) started on {me.username}.") 42 | logging.info(LOG_STR) 43 | 44 | async def stop(self, *args): 45 | await super().stop() 46 | logging.info("Bot stopped. Bye.") 47 | 48 | 49 | app = Bot() 50 | app.run() 51 | -------------------------------------------------------------------------------- /plugins/broadcast.py: -------------------------------------------------------------------------------- 1 | 2 | from pyrogram import Client, filters 3 | import datetime 4 | import time 5 | from database.users_chats_db import db 6 | from info import ADMINS 7 | from utils import broadcast_messages 8 | import asyncio 9 | 10 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply) 11 | # https://t.me/GetTGLink/4178 12 | async def verupikkals(bot, message): 13 | users = await db.get_all_users() 14 | b_msg = message.reply_to_message 15 | sts = await message.reply_text( 16 | text='Broadcasting your messages...' 17 | ) 18 | start_time = time.time() 19 | total_users = await db.total_users_count() 20 | done = 0 21 | blocked = 0 22 | deleted = 0 23 | failed =0 24 | 25 | success = 0 26 | async for user in users: 27 | pti, sh = await broadcast_messages(int(user['id']), b_msg) 28 | if pti: 29 | success += 1 30 | elif pti == False: 31 | if sh == "Bocked": 32 | blocked+=1 33 | elif sh == "Deleted": 34 | deleted += 1 35 | elif sh == "Error": 36 | failed += 1 37 | done += 1 38 | await asyncio.sleep(2) 39 | if not done % 20: 40 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 41 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 42 | 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}") -------------------------------------------------------------------------------- /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 | async def banned_users(_, client, message: Message): 8 | return ( 9 | message.from_user is not None or not message.sender_chat 10 | ) and message.from_user.id in temp.BANNED_USERS 11 | 12 | banned_user = filters.create(banned_users) 13 | 14 | async def disabled_chat(_, client, message: Message): 15 | return message.chat.id in temp.BANNED_CHATS 16 | 17 | disabled_group=filters.create(disabled_chat) 18 | 19 | 20 | @Client.on_message(filters.private & banned_user & filters.incoming) 21 | async def ban_reply(bot, message): 22 | ban = await db.get_ban_status(message.from_user.id) 23 | await message.reply(f'Sorry Dude, You are Banned to use be. \nBan Reason: {ban["ban_reason"]}') 24 | 25 | @Client.on_message(filters.group & disabled_group & filters.incoming) 26 | async def grp_bd(bot, message): 27 | buttons = [[ 28 | InlineKeyboardButton('𝙾𝚆𝙽𝙴𝚁', url=f'https://t.me/{SUPPORT_CHAT}') 29 | ]] 30 | reply_markup=InlineKeyboardMarkup(buttons) 31 | vazha = await db.get_chat(message.chat.id) 32 | k = await message.reply( 33 | text=f"CHAT NOT ALLOWED 🐞\n\n 𝙼𝚈 𝙾𝚆𝙽𝙴𝚁 𝙷𝙰𝚂 𝚁𝙴𝚂𝚃𝚁𝙸𝙲𝚃𝙴𝙳 𝙼𝙴 𝙵𝚁𝙾𝙼 𝚆𝙾𝚁𝙺𝙸𝙽𝙶 𝙷𝙴𝚁𝙴 ! 𝙸𝙵 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝚃𝙾 𝙺𝙽𝙾𝚆 𝙼𝙾𝚁𝙴 𝙲𝙾𝙽𝚃𝙰𝙲𝚃 𝙾𝚆𝙽𝙴𝚁..\nReason : {vazha['reason']}.", 34 | reply_markup=reply_markup) 35 | try: 36 | await k.pin() 37 | except: 38 | pass 39 | await bot.leave_chat(message.chat.id) 40 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /database/filters_mdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from info import DATABASE_URI, DATABASE_NAME 3 | import logging 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.ERROR) 6 | 7 | myclient = pymongo.MongoClient(DATABASE_URI) 8 | mydb = myclient[DATABASE_NAME] 9 | 10 | 11 | 12 | async def add_filter(grp_id, text, reply_text, btn, file, alert): 13 | mycol = mydb[str(grp_id)] 14 | # mycol.create_index([('text', 'text')]) 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_filter(group_id, name): 31 | mycol = mydb[str(group_id)] 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_filters(group_id): 50 | mycol = mydb[str(group_id)] 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_filter(message, text, group_id): 64 | mycol = mydb[str(group_id)] 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 filter anymore.", 72 | quote=True, 73 | parse_mode="md" 74 | ) 75 | else: 76 | await message.reply_text("Couldn't find that filter!", quote=True) 77 | 78 | 79 | async def del_all(message, group_id, title): 80 | if str(group_id) not in mydb.list_collection_names(): 81 | await message.edit_text(f"Nothing to remove in {title}!") 82 | return 83 | 84 | mycol = mydb[str(group_id)] 85 | try: 86 | mycol.drop() 87 | await message.edit_text(f"All filters from {title} has been removed") 88 | except: 89 | await message.edit_text("Couldn't remove all filters from group!") 90 | return 91 | 92 | 93 | async def count_filters(group_id): 94 | mycol = mydb[str(group_id)] 95 | 96 | count = mycol.count() 97 | if count == 0: 98 | return False 99 | else: 100 | return count 101 | 102 | 103 | async def filter_stats(): 104 | collections = mydb.list_collection_names() 105 | 106 | if "CONNECTION" in collections: 107 | collections.remove("CONNECTION") 108 | 109 | totalcount = 0 110 | for collection in collections: 111 | mycol = mydb[collection] 112 | count = mycol.count() 113 | totalcount += count 114 | 115 | totalcollections = len(collections) 116 | 117 | return totalcollections, totalcount 118 | -------------------------------------------------------------------------------- /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 occured!', 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 occured!', 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 | if group_id != None: 66 | return int(group_id) 67 | else: 68 | return None 69 | 70 | 71 | async def all_connections(user_id): 72 | query = mycol.find_one( 73 | { "_id": user_id }, 74 | { "_id": 0, "active_group": 0 } 75 | ) 76 | if query is not None: 77 | return [x["group_id"] for x in query["group_details"]] 78 | else: 79 | return None 80 | 81 | 82 | async def if_active(user_id, group_id): 83 | query = mycol.find_one( 84 | { "_id": user_id }, 85 | { "_id": 0, "group_details": 0 } 86 | ) 87 | return query is not None and query['active_group'] == group_id 88 | 89 | 90 | async def make_active(user_id, group_id): 91 | update = mycol.update_one( 92 | {'_id': user_id}, 93 | {"$set": {"active_group" : group_id}} 94 | ) 95 | return update.modified_count != 0 96 | 97 | 98 | async def make_inactive(user_id): 99 | update = mycol.update_one( 100 | {'_id': user_id}, 101 | {"$set": {"active_group" : None}} 102 | ) 103 | return update.modified_count != 0 104 | 105 | 106 | async def delete_connection(user_id, group_id): 107 | 108 | try: 109 | update = mycol.update_one( 110 | {"_id": user_id}, 111 | {"$pull" : { "group_details" : {"group_id":group_id} } } 112 | ) 113 | if update.modified_count == 0: 114 | return False 115 | query = mycol.find_one( 116 | { "_id": user_id }, 117 | { "_id": 0 } 118 | ) 119 | if len(query["group_details"]) >= 1: 120 | if query['active_group'] == group_id: 121 | prvs_group_id = query["group_details"][len(query["group_details"]) - 1]["group_id"] 122 | 123 | mycol.update_one( 124 | {'_id': user_id}, 125 | {"$set": {"active_group" : prvs_group_id}} 126 | ) 127 | else: 128 | mycol.update_one( 129 | {'_id': user_id}, 130 | {"$set": {"active_group" : None}} 131 | ) 132 | return True 133 | except Exception as e: 134 | logger.exception(f'Some error occured! {e}', exc_info=True) 135 | return False 136 | 137 | -------------------------------------------------------------------------------- /info.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import environ 3 | 4 | id_pattern = re.compile(r'^.\d+$') 5 | def is_enabled(value, default): 6 | if value.lower() in ["true", "yes", "1", "enable", "y"]: 7 | return True 8 | elif value.lower() in ["false", "no", "0", "disable", "n"]: 9 | return False 10 | else: 11 | return default 12 | 13 | # Bot information 14 | SESSION = environ.get('SESSION', 'Media_search') 15 | API_ID = int(environ['API_ID']) 16 | API_HASH = environ['API_HASH'] 17 | BOT_TOKEN = environ['BOT_TOKEN'] 18 | 19 | # Bot settings 20 | CACHE_TIME = int(environ.get('CACHE_TIME', 300)) 21 | USE_CAPTION_FILTER = bool(environ.get('USE_CAPTION_FILTER', False)) 22 | PICS = (environ.get('PICS', 'https://telegra.ph/file/3d87cdb638b5444198c59.jpg https://telegra.ph/file/2140af3c0cb1c848ef5a0.jpg https://telegra.ph/file/f5c3720b2ce9d1d97d59f.jpg')).split() 23 | 24 | # Admins, Channels & Users 25 | ADMINS = [int(admin) if id_pattern.search(admin) else admin for admin in environ.get('ADMINS', '').split()] 26 | CHANNELS = [int(ch) if id_pattern.search(ch) else ch for ch in environ.get('CHANNELS', '0').split()] 27 | auth_users = [int(user) if id_pattern.search(user) else user for user in environ.get('AUTH_USERS', '').split()] 28 | AUTH_USERS = (auth_users + ADMINS) if auth_users else [] 29 | auth_channel = environ.get('AUTH_CHANNEL') 30 | auth_grp = environ.get('AUTH_GROUP') 31 | AUTH_CHANNEL = int(auth_channel) if auth_channel and id_pattern.search(auth_channel) else None 32 | AUTH_GROUPS = [int(ch) for ch in auth_grp.split()] if auth_grp else None 33 | 34 | # MongoDB information 35 | DATABASE_URI = environ.get('DATABASE_URI', "") 36 | DATABASE_NAME = environ.get('DATABASE_NAME', "Rajappan") 37 | COLLECTION_NAME = environ.get('COLLECTION_NAME', 'Telegram_files') 38 | 39 | # Others 40 | LOG_CHANNEL = int(environ.get('LOG_CHANNEL', 0)) 41 | SUPPORT_CHAT = environ.get('SUPPORT_CHAT', 'TeamEvamaria') 42 | P_TTI_SHOW_OFF = is_enabled((environ.get('P_TTI_SHOW_OFF', "False")), False) 43 | IMDB = is_enabled((environ.get('IMDB', "True")), True) 44 | SINGLE_BUTTON = is_enabled((environ.get('SINGLE_BUTTON', "False")), False) 45 | CUSTOM_FILE_CAPTION = environ.get("CUSTOM_FILE_CAPTION", None) 46 | IMDB_TEMPLATE = environ.get("IMDB_TEMPLATE", "Query: {query} \n‌IMDb Data:\n\n🏷 Title: {title}\n🎭 Genres: {genres}\n📆 Year: {year}\n🌟 Rating: {rating} / 10") 47 | LONG_IMDB_DESCRIPTION = is_enabled(environ.get("LONG_IMDB_DESCRIPTION", "False"), False) 48 | SPELL_CHECK_REPLY = is_enabled(environ.get("SPELL_CHECK_REPLY", "True"), True) 49 | MAX_LIST_ELM = environ.get("MAX_LIST_ELM", None) 50 | INDEX_REQ_CHANNEL = int(environ.get('INDEX_REQ_CHANNEL', 'LOG_CHANNEL')) 51 | 52 | LOG_STR = "Current Cusomized Configurations are:-\n" 53 | LOG_STR += ("IMDB Results are enabled, Bot will be showing imdb details for you queries.\n" if IMDB else "IMBD Results are disabled.\n") 54 | 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") 55 | LOG_STR += ("SINGLE_BUTTON is Found, filename and files size will be shown in a single button instead of two seperate buttons\n" if SINGLE_BUTTON else "SINGLE_BUTTON is disabled , filename and file_sixe will be shown as diffrent buttons\n") 56 | 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") 57 | LOG_STR += ("Long IMDB storyline enabled." if LONG_IMDB_DESCRIPTION else "LONG_IMDB_DESCRIPTION is disabled , Plot will be shorter.\n") 58 | 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") 59 | 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") 60 | LOG_STR += f"Your Currect IMDB template is {IMDB_TEMPLATE}" 61 | -------------------------------------------------------------------------------- /database/users_chats_db.py: -------------------------------------------------------------------------------- 1 | # https://github.com/odysseusmax/animated-lamp/blob/master/bot/database/database.py 2 | import motor.motor_asyncio 3 | from info import DATABASE_NAME, DATABASE_URI 4 | 5 | class Database: 6 | 7 | def __init__(self, uri, database_name): 8 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri) 9 | self.db = self._client[database_name] 10 | self.col = self.db.users 11 | self.grp = self.db.groups 12 | 13 | 14 | def new_user(self, id, name): 15 | return dict( 16 | id = id, 17 | name = name, 18 | ban_status=dict( 19 | is_banned=False, 20 | ban_reason="", 21 | ), 22 | ) 23 | 24 | 25 | def new_group(self, id, title): 26 | return dict( 27 | id = id, 28 | title = title, 29 | chat_status=dict( 30 | is_disabled=False, 31 | reason="", 32 | ), 33 | ) 34 | 35 | async def add_user(self, id, name): 36 | user = self.new_user(id, name) 37 | await self.col.insert_one(user) 38 | 39 | async def is_user_exist(self, id): 40 | user = await self.col.find_one({'id':int(id)}) 41 | return bool(user) 42 | 43 | async def total_users_count(self): 44 | count = await self.col.count_documents({}) 45 | return count 46 | 47 | async def remove_ban(self, id): 48 | ban_status = dict( 49 | is_banned=False, 50 | ban_reason='' 51 | ) 52 | await self.col.update_one({'id': id}, {'$set': {'ban_status': ban_status}}) 53 | 54 | async def ban_user(self, user_id, ban_reason="No Reason"): 55 | ban_status = dict( 56 | is_banned=True, 57 | ban_reason=ban_reason 58 | ) 59 | await self.col.update_one({'id': user_id}, {'$set': {'ban_status': ban_status}}) 60 | 61 | async def get_ban_status(self, id): 62 | default = dict( 63 | is_banned=False, 64 | ban_reason='' 65 | ) 66 | user = await self.col.find_one({'id':int(id)}) 67 | if not user: 68 | return default 69 | return user.get('ban_status', default) 70 | 71 | async def get_all_users(self): 72 | return self.col.find({}) 73 | 74 | 75 | async def delete_user(self, user_id): 76 | await self.col.delete_many({'id': int(user_id)}) 77 | 78 | 79 | async def get_banned(self): 80 | users = self.col.find({'ban_status.is_banned': True}) 81 | chats = self.grp.find({'chat_status.is_disabled': True}) 82 | b_chats = [chat['id'] async for chat in chats] 83 | b_users = [user['id'] async for user in users] 84 | return b_users, b_chats 85 | 86 | 87 | 88 | async def add_chat(self, chat, title): 89 | chat = self.new_group(chat, title) 90 | await self.grp.insert_one(chat) 91 | 92 | 93 | async def get_chat(self, chat): 94 | chat = await self.grp.find_one({'id':int(chat)}) 95 | if not chat: 96 | return False 97 | else: 98 | return chat.get('chat_status') 99 | 100 | 101 | async def re_enable_chat(self, id): 102 | chat_status=dict( 103 | is_disabled=False, 104 | reason="", 105 | ) 106 | await self.grp.update_one({'id': int(id)}, {'$set': {'chat_status': chat_status}}) 107 | 108 | 109 | async def disable_chat(self, chat, reason="No Reason"): 110 | chat_status=dict( 111 | is_disabled=True, 112 | reason=reason, 113 | ) 114 | await self.grp.update_one({'id': int(chat)}, {'$set': {'chat_status': chat_status}}) 115 | 116 | 117 | async def total_chat_count(self): 118 | count = await self.grp.count_documents({}) 119 | return count 120 | 121 | 122 | async def get_all_chats(self): 123 | return self.grp.find({}) 124 | 125 | 126 | async def get_db_size(self): 127 | return (await self.db.command("dbstats"))['dataSize'] 128 | 129 | 130 | db = Database(DATABASE_URI, DATABASE_NAME) 131 | -------------------------------------------------------------------------------- /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 5 | from database.ia_filterdb import get_search_results 6 | from utils import is_subscribed, get_size 7 | from info import CACHE_TIME, AUTH_USERS, AUTH_CHANNEL, CUSTOM_FILE_CAPTION 8 | 9 | logger = logging.getLogger(__name__) 10 | cache_time = 0 if AUTH_USERS or AUTH_CHANNEL else CACHE_TIME 11 | 12 | 13 | @Client.on_inline_query(filters.user(AUTH_USERS) if AUTH_USERS else None) 14 | async def answer(bot, query): 15 | """Show search results for given inline query""" 16 | 17 | if AUTH_CHANNEL and not await is_subscribed(bot, query): 18 | await query.answer(results=[], 19 | cache_time=0, 20 | switch_pm_text='You have to subscribe my channel to use the bot', 21 | switch_pm_parameter="subscribe") 22 | return 23 | 24 | results = [] 25 | if '|' in query.query: 26 | string, file_type = query.query.split('|', maxsplit=1) 27 | string = string.strip() 28 | file_type = file_type.strip().lower() 29 | else: 30 | string = query.query.strip() 31 | file_type = None 32 | 33 | offset = int(query.offset or 0) 34 | reply_markup = get_reply_markup(query=string) 35 | files, next_offset, total = await get_search_results(string, 36 | file_type=file_type, 37 | max_results=10, 38 | offset=offset) 39 | 40 | for file in files: 41 | title=file.file_name 42 | size=get_size(file.file_size) 43 | f_caption=file.caption 44 | if CUSTOM_FILE_CAPTION: 45 | try: 46 | f_caption=CUSTOM_FILE_CAPTION.format(file_name=title, file_size=size, file_caption=f_caption) 47 | except Exception as e: 48 | logger.exception(e) 49 | f_caption=f_caption 50 | if f_caption is None: 51 | f_caption = f"{file.file_name}" 52 | results.append( 53 | InlineQueryResultCachedDocument( 54 | title=file.file_name, 55 | file_id=file.file_id, 56 | caption=f_caption, 57 | description=f'Size: {get_size(file.file_size)}\nType: {file.file_type}', 58 | reply_markup=reply_markup)) 59 | 60 | if results: 61 | switch_pm_text = f"{emoji.FILE_FOLDER} Results - {total}" 62 | if string: 63 | switch_pm_text += f" for {string}" 64 | try: 65 | await query.answer(results=results, 66 | is_personal = True, 67 | cache_time=cache_time, 68 | switch_pm_text=switch_pm_text, 69 | switch_pm_parameter="start", 70 | next_offset=str(next_offset)) 71 | except QueryIdInvalid: 72 | pass 73 | except Exception as e: 74 | logging.exception(str(e)) 75 | await query.answer(results=[], is_personal=True, 76 | cache_time=cache_time, 77 | switch_pm_text=str(e)[:63], 78 | switch_pm_parameter="error") 79 | else: 80 | switch_pm_text = f'{emoji.CROSS_MARK} No results' 81 | if string: 82 | switch_pm_text += f' for "{string}"' 83 | 84 | await query.answer(results=[], 85 | is_personal = True, 86 | cache_time=cache_time, 87 | switch_pm_text=switch_pm_text, 88 | switch_pm_parameter="okay") 89 | 90 | 91 | def get_reply_markup(query): 92 | buttons = [ 93 | [ 94 | InlineKeyboardButton('♻️ 𝗦𝗲𝗮𝗿𝗰𝗵 𝗔𝗴𝗮𝗶𝗻 ♻️', switch_inline_query_current_chat=query) 95 | ],[ 96 | InlineKeyboardButton('♥️ 𝗖𝗵𝗮𝗻𝗻𝗲𝗹 ♥️', url='https://t.me/+veUIdIW2CQ5mOGU5') 97 | ] 98 | ] 99 | return InlineKeyboardMarkup(buttons) 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Technical Cynite 3 |

4 |

5 | ᎪႮͲϴ-ҒᏆᏞͲᎬᎡ 6 |

7 | 8 | 9 | 10 | [![Stars](https://img.shields.io/github/stars/CyniteOfficial/Auto-Filter-Bot?style=flat-square&color=orange)](https://github.com/CyniteOfficial/Auto-Filter-Bot/stargazers) 11 | [![Forks](https://img.shields.io/github/forks/CyniteOfficial/Auto-Filter-Bot?style=flat-square&color=blue)](https://github.com/CyniteOfficial/Auto-Filter-Bot/fork) 12 | [![Size](https://img.shields.io/github/repo-size/CyniteOfficial/Auto-Filter-Bot?style=flat-square&color=black)](https://github.com/CyniteOfficial/Auto-Filter-Bot) 13 | [![Open Source happy ](https://badges.frapsoft.com/os/v2/open-source.svg?v=110)](https://github.com/Aadhi000/Ajax) 14 | [![Contributors](https://img.shields.io/github/contributors/Aadhi000/Auto-Filter-Bot?style=flat-square&color=green)](https://github.com/CyniteOfficial/Auto-Filter-Bot/graphs/contributors) 15 | ## Features 16 | 17 | - [x] Auto Filter 18 | - [x] Manual Filter 19 | - [x] IMDB 20 | - [x] Admin Commands 21 | - [x] Broadcast 22 | - [x] Index 23 | - [x] IMDB search 24 | - [x] Inline Search 25 | - [x] Random pics 26 | - [x] ids and User info 27 | - [x] Stats, Users, Chats, Ban, Unban, Leave, Disable, Channel 28 | - [x] Spelling Check Feature 29 | 30 | ## Variables 31 | 32 | ### Required Variables 33 | * `BOT_TOKEN`: Create a bot using [@BotFather](https://telegram.dog/BotFather), and get the Telegram API token. 34 | * `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) 35 | * `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) 36 | * `CHANNELS`: Username or ID of channel or group. Separate multiple IDs by space 37 | * `ADMINS`: Username or ID of Admin. Separate multiple Admins by space 38 | * `DATABASE_URI`: [mongoDB](https://www.mongodb.com) URI. Get this value from [mongoDB](https://www.mongodb.com). 39 | * `DATABASE_NAME`: Name of the database in [mongoDB](https://www.mongodb.com). For more help watch this 40 | * `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. 41 | ### Optional Variables 42 | * `PICS`: Telegraph links of images to show in start message.( Multiple images can be used seperated by space ) 43 | 44 | 45 | ## Deploy 46 | You can deploy this bot anywhere. 47 | 48 | 49 | 50 |
Deploy To Heroku 51 |

52 |
53 |
54 | Deploy 55 | 56 |

57 |
58 | 59 |
Deploy To VPS 60 |

61 |

 62 | git clone https://github.com/CyniteOfficial/Auto-Filter-Bot
 63 | # Install Packages
 64 | pip3 install -r requirements.txt
 65 | Edit info.py with variables as given below then run bot
 66 | python3 bot.py
 67 | 
68 |

69 |
70 | 71 | 72 | ## Commands 73 | ``` 74 | • /logs - to get the rescent errors 75 | • /stats - to get status of files in db. 76 | * /filter - add manual filters 77 | * /filters - view filters 78 | * /connect - connect to PM. 79 | * /disconnect - disconnect from PM 80 | * /del - delete a filter 81 | * /delall - delete all filters 82 | * /deleteall - delete all index(autofilter) 83 | * /delete - delete a specific file from index. 84 | * /info - get user info 85 | * /id - get tg ids. 86 | * /imdb - fetch info from imdb. 87 | • /users - to get list of my users and ids. 88 | • /chats - to get list of the my chats and ids 89 | • /index - to add files from a channel 90 | • /leave - to leave from a chat. 91 | • /disable - do disable a chat. 92 | * /enable - re-enable chat. 93 | • /ban - to ban a user. 94 | • /unban - to unban a user. 95 | • /channel - to get list of total connected channels 96 | • /broadcast - to broadcast a message to Cynite users 97 | ``` 98 | 99 | Cʀᴇᴅɪᴛ ›› [𝐎𝐩𝐮𝐬 𝐓𝐞𝐜𝐡𝐳](https://t.me/OpusTechz) || [𝐂𝐨𝐧𝐭𝐚𝐜𝐭](https://t.me/CyniteOfficial) 100 | 𝙲𝙷𝙰𝙽𝙽𝙴𝙻 ›› [𝐂𝐲𝐧𝐢𝐭𝐞 𝐁𝐨𝐭𝐬](https://t.me/CyniteBots) 101 | -------------------------------------------------------------------------------- /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 11 | 12 | logger = logging.getLogger(__name__) 13 | logger.setLevel(logging.INFO) 14 | 15 | 16 | client = AsyncIOMotorClient(DATABASE_URI) 17 | db = client[DATABASE_NAME] 18 | instance = Instance.from_db(db) 19 | 20 | @instance.register 21 | class Media(Document): 22 | file_id = fields.StrField(attribute='_id') 23 | file_ref = fields.StrField(allow_none=True) 24 | file_name = fields.StrField(required=True) 25 | file_size = fields.IntField(required=True) 26 | file_type = fields.StrField(allow_none=True) 27 | mime_type = fields.StrField(allow_none=True) 28 | caption = fields.StrField(allow_none=True) 29 | 30 | class Meta: 31 | collection_name = COLLECTION_NAME 32 | 33 | 34 | async def save_file(media): 35 | """Save file in database""" 36 | 37 | # TODO: Find better way to get same file_id for same media to avoid duplicates 38 | file_id, file_ref = unpack_new_file_id(media.file_id) 39 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 40 | try: 41 | file = Media( 42 | file_id=file_id, 43 | file_ref=file_ref, 44 | file_name=file_name, 45 | file_size=media.file_size, 46 | file_type=media.file_type, 47 | mime_type=media.mime_type, 48 | caption=media.caption.html if media.caption else None, 49 | ) 50 | except ValidationError: 51 | logger.exception('Error occurred while saving file in database') 52 | return False, 2 53 | else: 54 | try: 55 | await file.commit() 56 | except DuplicateKeyError: 57 | logger.warning(media.file_name + " is already saved in database") 58 | return False, 0 59 | else: 60 | logger.info(media.file_name + " is saved in database") 61 | return True, 1 62 | 63 | 64 | 65 | async def get_search_results(query, file_type=None, max_results=10, offset=0, filter=False): 66 | """For given query return (results, next_offset)""" 67 | 68 | query = query.strip() 69 | #if filter: 70 | #better ? 71 | #query = query.replace(' ', r'(\s|\.|\+|\-|_)') 72 | #raw_pattern = r'(\s|_|\-|\.|\+)' + query + r'(\s|_|\-|\.|\+)' 73 | if not query: 74 | raw_pattern = '.' 75 | elif ' ' not in query: 76 | raw_pattern = r'(\b|[\.\+\-_])' + query + r'(\b|[\.\+\-_])' 77 | else: 78 | raw_pattern = query.replace(' ', r'.*[\s\.\+\-_]') 79 | 80 | try: 81 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 82 | except: 83 | return [] 84 | 85 | if USE_CAPTION_FILTER: 86 | filter = {'$or': [{'file_name': regex}, {'caption': regex}]} 87 | else: 88 | filter = {'file_name': regex} 89 | 90 | if file_type: 91 | filter['file_type'] = file_type 92 | 93 | total_results = await Media.count_documents(filter) 94 | next_offset = offset + max_results 95 | 96 | if next_offset > total_results: 97 | next_offset = '' 98 | 99 | cursor = Media.find(filter) 100 | # Sort by recent 101 | cursor.sort('$natural', -1) 102 | # Slice files according to offset and max results 103 | cursor.skip(offset).limit(max_results) 104 | # Get list of files 105 | files = await cursor.to_list(length=max_results) 106 | 107 | return files, next_offset, total_results 108 | 109 | 110 | 111 | async def get_file_details(query): 112 | filter = {'file_id': query} 113 | cursor = Media.find(filter) 114 | filedetails = await cursor.to_list(length=1) 115 | return filedetails 116 | 117 | 118 | def encode_file_id(s: bytes) -> str: 119 | r = b"" 120 | n = 0 121 | 122 | for i in s + bytes([22]) + bytes([4]): 123 | if i == 0: 124 | n += 1 125 | else: 126 | if n: 127 | r += b"\x00" + bytes([n]) 128 | n = 0 129 | 130 | r += bytes([i]) 131 | 132 | return base64.urlsafe_b64encode(r).decode().rstrip("=") 133 | 134 | 135 | def encode_file_ref(file_ref: bytes) -> str: 136 | return base64.urlsafe_b64encode(file_ref).decode().rstrip("=") 137 | 138 | 139 | def unpack_new_file_id(new_file_id): 140 | """Return file_id, file_ref""" 141 | decoded = FileId.decode(new_file_id) 142 | file_id = encode_file_id( 143 | pack( 144 | "{} Iam A Simple Auto Filter + Manual Filter + Extra Features Bot. I Can Provide Movies In Telegram Groups.I Can Also Add Filters In Telegram Groups. Just Add Me To Your Group And Enjoy""" 4 | HELP_TXT = """𝙷𝙴𝚈 {} 5 | 𝙷𝙴𝚁𝙴 𝙸𝚂 𝚃𝙷𝙴 𝙷𝙴𝙻𝙿 𝙵𝙾𝚁 𝙼𝚈 𝙲𝙾𝙼𝙼𝙰𝙽𝙳𝚂.""" 6 | ABOUT_TXT = """✮ 𝙼𝚈 𝙽𝙰𝙼𝙴: {} 7 | ✮ 𝙲𝚁𝙴𝙰𝚃𝙾𝚁: нαямαи 8 | ✮ 𝙻𝙸𝙱𝚁𝙰𝚁𝚈: 𝙿𝚈𝚁𝙾𝙶𝚁𝙰𝙼 9 | ✮ 𝙻𝙰𝙽𝙶𝚄𝙰𝙶𝙴: 𝙿𝚈𝚃𝙷𝙾𝙽 𝟹 10 | ✮ 𝙳𝙰𝚃𝙰 𝙱𝙰𝚂𝙴: 𝙼𝙾𝙽𝙶𝙾 𝙳𝙱 11 | ✮ 𝙱𝙾𝚃 𝚂𝙴𝚁𝚅𝙴𝚁: 𝙷𝙴𝚁𝙾𝙺𝚄 12 | ✮ 𝙱𝚄𝙸𝙻𝙳 𝚂𝚃𝙰𝚃𝚄𝚂: v1.0.2 [ 𝙱𝙴𝚃𝙰 ]""" 13 | 14 | PRIVATEBOT_TXT = """𝙿𝚁𝙸𝚅𝙰𝚃𝙴 𝙱𝙾𝚃 𝙵𝙾𝚁 𝚈𝙾𝚄 15 | ›› 𝙳𝙾 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝙰 𝙱𝙾𝚃 𝚂𝙰𝙼𝙴 𝙻𝙸𝙺𝙴 𝚃𝙷𝙸𝚂 16 | ›› 𝚆𝙸𝚃𝙷 𝙰𝙻𝙻 𝚈𝙾𝚄𝚁 𝙲𝚁𝙴𝙳𝙸𝚃𝚂 17 | ›› 𝚆𝙸𝚃𝙷 𝚈𝙾𝚄𝚁 𝙾𝚆𝙽𝙴𝚁𝚂𝙷𝙸𝙿 18 | ›› 𝙲𝙾𝙽𝚃𝙰𝙲𝚃 𝙼𝙴 нαямαи""" 19 | 20 | SOURCE_TXT = """Donation 21 | 22 | ⪼ 𝐘𝐨𝐮 𝐂𝐚𝐧 𝐃𝐨𝐧𝐚𝐭𝐞 𝐀𝐧𝐲 𝐀𝐦𝐨𝐮𝐧𝐭 𝐘𝐨𝐮 𝐇𝐚𝐯𝐞 💳. 23 | 24 | ━━━━━━━━━᚜ Payment Methods ᚛━━━━━━━━━ 25 | 26 | ✮ 𝗚𝗼𝗼𝗴𝗹𝗲𝗣𝗮𝘆 27 | ✮ 𝗣𝗮𝘆𝘁𝗺 28 | ✮ 𝗣𝗵𝗼𝗻𝗲𝗣𝗲 29 | ✮ 𝗣𝗮𝘆𝗣𝗮𝗹 30 | 31 | _𝐂𝐨𝐧𝐭𝐚𝐜𝐭 𝐌𝐞 𝐅𝐨𝐫 𝐊𝐧𝐨𝐰 𝐀𝐛𝐨𝐮𝐭 𝐓𝐡𝐞 𝐏𝐚𝐲𝐦𝐞𝐧𝐭 𝐈𝐧𝐟𝐨_ 32 | ━━━━━━━━━━━━᚜ нαямαи ᚛━━━━━━━━━━━━""" 33 | MANUELFILTER_TXT = """Help: Filters 34 | 35 | - Filter is the feature were users can set automated replies for a particular keyword and Zsearcher will respond whenever a keyword is found the message 36 | 37 | NOTE: 38 | 1. Zsᴇᴀʀᴄʜᴇʀ should have admin privillage. 39 | 2. only admins can add filters in a chat. 40 | 3. alert buttons have a limit of 64 characters. 41 | 42 | Commands and Usage: 43 | ➾ /filter - add a filter in chat 44 | ➾ /filters - list all the filters of a chat 45 | ➾ /del - delete a specific filter in chat 46 | ➾ /delall - delete the whole filters in a chat (chat owner only)""" 47 | BUTTON_TXT = """Help: Buttons 48 | 49 | - Zsearcher Supports both url and alert inline buttons. 50 | 51 | NOTE: 52 | 1. Telegram will not allows you to send buttons without any content, so content is mandatory. 53 | 2. Zsᴇᴀʀᴄʜᴇʀ supports buttons with any telegram media type. 54 | 3. Buttons should be properly parsed as markdown format 55 | 56 | URL buttons: 57 | [Button Text](buttonurl:https://t.me/Cynitebots) 58 | 59 | Alert buttons: 60 | [Button Text](buttonalert:This is an alert message)""" 61 | AUTOFILTER_TXT = """Help: Auto Filter 62 | 63 | NOTE: 64 | 1. Make me the admin of your channel if it's private. 65 | 2. make sure that your channel does not contains camrips, porn and fake files. 66 | 3. Forward the last message to me with quotes. 67 | I'll add all the files in that channel to my db.""" 68 | CONNECTION_TXT = """Help: Connections 69 | 70 | - Used to connect bot to PM for managing filters 71 | - it helps to avoid spamming in groups. 72 | 73 | NOTE: 74 | 1. Only admins can add a connection. 75 | 2. Send /connect for connecting me to ur PM 76 | 77 | Commands and Usage: 78 | ➾ /connect - connect a particular chat to your PM 79 | ➾ /disconnect - disconnect from a chat 80 | ➾ /connections - list all your connections""" 81 | EXTRAMOD_TXT = """Help: Extra Modules 82 | 83 | NOTE: 84 | These are the extra features of Zsᴇᴀʀᴄʜᴇʀ 85 | 86 | Commands and Usage: 87 | ➾ /id - get id of a specifed user. 88 | ➾ /info - get information about a user. 89 | ➾ /imdb - get the film information from IMDb source. 90 | ➾ /search - get the film information from various sources.""" 91 | ADMIN_TXT = """Help: Admin mods 92 | 93 | NOTE: 94 | This module only works for my OᗯᑎEᖇ⚡ 95 | 96 | Commands and Usage: 97 | ➾ /logs - to get the rescent errors 98 | ➾ /stats - to get status of files in db. 99 | ➾ /delete - to delete a specific file from db. 100 | ➾ /users - to get list of my users and ids. 101 | ➾ /chats - to get list of the my chats and ids 102 | ➾ /leave - to leave from a chat. 103 | ➾ /disable - do disable a chat. 104 | ➾ /ban - to ban a user. 105 | ➾ /unban - to unban a user. 106 | ➾ /channel - to get list of total connected channels 107 | ➾ /broadcast - to broadcast a message to all users""" 108 | STATUS_TXT = """✮ 𝚃𝙾𝚃𝙰𝙻 𝙵𝙸𝙻𝙴𝚂: {} 109 | ✮ 𝚃𝙾𝚃𝙰𝙻 𝚄𝚂𝙴𝚁𝚂: {} 110 | ✮ 𝚃𝙾𝚃𝙰𝙻 𝙲𝙷𝙰𝚃𝚂: {} 111 | ✮ 𝚄𝚂𝙴𝙳 𝚂𝚃𝙾𝚁𝙰𝙶𝙴: {} 𝙼𝚒𝙱 112 | ✮ 𝙵𝚁𝙴𝙴 𝚂𝚃𝙾𝚁𝙰𝙶𝙴: {} 𝙼𝚒𝙱""" 113 | LOG_TEXT_G = """#𝐍𝐞𝐰𝐆𝐫𝐨𝐮𝐩 114 | ✮ 𝐆𝐫𝐨𝐮𝐩 ›› {}({}) 115 | ✮ 𝐓𝐨𝐭𝐚𝐥 𝐌𝐞𝐦𝐛𝐞𝐫𝐬 ›› {} 116 | ✮ 𝐀𝐝𝐝𝐞𝐝 𝐁𝐲 ›› {} 117 | """ 118 | LOG_TEXT_P = """#𝐍𝐞𝐰𝐔𝐬𝐞𝐫 119 | ✮ 𝐈𝐃 ›› {} 120 | ✮ 𝐍𝐚𝐦𝐞 ›› {} 121 | """ 122 | CARBON_TXT = """ 𝙲𝙰𝚁𝙱𝙾𝙽 𝙼𝙾𝙳𝚄𝙻𝙴 123 | 124 | 𝚈𝙾𝚄 𝙲𝙰𝙽 𝙱𝙴𝙰𝚄𝚃𝙸𝙵𝚈 𝚈𝙾𝚄𝚁 𝙲𝙾𝙳𝙴𝚂 𝙱𝚈 𝚄𝚂𝙸𝙽𝙶 𝚃𝙷𝚂 𝙵𝙴𝙰𝚃𝚄𝚁𝙴... 125 | 126 | 𝙲𝙾𝙼𝙼𝙰𝙽𝙳.! 127 | /carbon ›› 𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰𝙽𝚈 𝚃𝙴𝚇𝚃 𝙼𝙴𝚂𝚂𝙰𝙶𝙴 128 | 129 | 𝚆𝙾𝚁𝙺𝚂 𝙾𝙽 𝙱𝙾𝚃𝙷 𝙶𝚁𝙾𝚄𝙿 𝙰𝙽𝙳 𝙿𝙼 130 | 𝙲𝚁𝙴𝙳𝙸𝚃𝚂 ›› ᴛᴇᴄʜɴɪᴄᴀʟ-ᴄʏɴɪᴛᴇ""" 131 | -------------------------------------------------------------------------------- /plugins/connection.py: -------------------------------------------------------------------------------- 1 | from pyrogram import filters, Client 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 | import logging 6 | logger = logging.getLogger(__name__) 7 | logger.setLevel(logging.ERROR) 8 | @Client.on_message((filters.private | filters.group) & filters.command('connect')) 9 | async def addconnection(client,message): 10 | userid = message.from_user.id if message.from_user else None 11 | if not userid: 12 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 13 | chat_type = message.chat.type 14 | 15 | if chat_type == "private": 16 | try: 17 | cmd, group_id = message.text.split(" ", 1) 18 | except: 19 | await message.reply_text( 20 | "Enter in correct format!\n\n" 21 | "/connect groupid\n\n" 22 | "Get your Group id by adding this bot to your group and use /id", 23 | quote=True 24 | ) 25 | return 26 | 27 | elif chat_type in ["group", "supergroup"]: 28 | group_id = message.chat.id 29 | 30 | try: 31 | st = await client.get_chat_member(group_id, userid) 32 | if ( 33 | st.status != "administrator" 34 | and st.status != "creator" 35 | and str(userid) not in ADMINS 36 | ): 37 | await message.reply_text("You should be an admin in Given group!", quote=True) 38 | return 39 | except Exception as e: 40 | logger.exception(e) 41 | await message.reply_text( 42 | "Invalid Group ID!\n\nIf correct, Make sure I'm present in your group!!", 43 | quote=True, 44 | ) 45 | 46 | return 47 | try: 48 | st = await client.get_chat_member(group_id, "me") 49 | if st.status == "administrator": 50 | ttl = await client.get_chat(group_id) 51 | title = ttl.title 52 | 53 | addcon = await add_connection(str(group_id), str(userid)) 54 | if addcon: 55 | await message.reply_text( 56 | f"Sucessfully connected to **{title}**\nNow manage your group from my pm !", 57 | quote=True, 58 | parse_mode="md" 59 | ) 60 | if chat_type in ["group", "supergroup"]: 61 | await client.send_message( 62 | userid, 63 | f"Connected to **{title}** !", 64 | parse_mode="md" 65 | ) 66 | else: 67 | await message.reply_text( 68 | "You're already connected to this chat!", 69 | quote=True 70 | ) 71 | else: 72 | await message.reply_text("Add me as an admin in group", quote=True) 73 | except Exception as e: 74 | logger.exception(e) 75 | await message.reply_text('Some error occured! Try again later.', quote=True) 76 | return 77 | 78 | 79 | @Client.on_message((filters.private | filters.group) & filters.command('disconnect')) 80 | async def deleteconnection(client,message): 81 | userid = message.from_user.id if message.from_user else None 82 | if not userid: 83 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 84 | chat_type = message.chat.type 85 | 86 | if chat_type == "private": 87 | await message.reply_text("Run /connections to view or disconnect from groups!", quote=True) 88 | 89 | elif chat_type in ["group", "supergroup"]: 90 | group_id = message.chat.id 91 | 92 | st = await client.get_chat_member(group_id, userid) 93 | if ( 94 | st.status != "administrator" 95 | and st.status != "creator" 96 | and str(userid) not in ADMINS 97 | ): 98 | return 99 | 100 | delcon = await delete_connection(str(userid), str(group_id)) 101 | if delcon: 102 | await message.reply_text("Successfully disconnected from this chat", quote=True) 103 | else: 104 | await message.reply_text("This chat isn't connected to me!\nDo /connect to connect.", quote=True) 105 | 106 | 107 | 108 | @Client.on_message(filters.private & filters.command(["connections"])) 109 | async def connections(client,message): 110 | userid = message.from_user.id 111 | 112 | groupids = await all_connections(str(userid)) 113 | if groupids is None: 114 | await message.reply_text( 115 | "There are no active connections!! Connect to some groups first.", 116 | quote=True 117 | ) 118 | return 119 | buttons = [] 120 | for groupid in groupids: 121 | try: 122 | ttl = await client.get_chat(int(groupid)) 123 | title = ttl.title 124 | active = await if_active(str(userid), str(groupid)) 125 | act = " - ACTIVE" if active else "" 126 | buttons.append( 127 | [ 128 | InlineKeyboardButton( 129 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}" 130 | ) 131 | ] 132 | ) 133 | except: 134 | pass 135 | if buttons: 136 | await message.reply_text( 137 | "Your connected group details ;\n\n", 138 | reply_markup=InlineKeyboardMarkup(buttons), 139 | quote=True 140 | ) 141 | else: 142 | await message.reply_text( 143 | "There are no active connections!! Connect to some groups first.", 144 | quote=True 145 | ) 146 | -------------------------------------------------------------------------------- /plugins/misc.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyrogram import Client, filters 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 == "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 ["group", "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 | # https://github.com/SpEcHiDe/PyroGramBot/blob/master/pyrobot/plugins/admemes/whois.py#L19 60 | status_message = await message.reply_text( 61 | "`𝗦𝗲𝗮𝗿𝗰𝗵𝗶𝗻𝗴 𝗨𝘀𝗲𝗿...`" 62 | ) 63 | await status_message.edit( 64 | "`𝗔𝗰𝗰𝗲𝘀𝘀𝗶𝗻𝗴 𝗜𝗻𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻...`" 65 | ) 66 | from_user = None 67 | from_user_id, _ = extract_user(message) 68 | try: 69 | from_user = await client.get_users(from_user_id) 70 | except Exception as error: 71 | await status_message.edit(str(error)) 72 | return 73 | if from_user is None: 74 | return await status_message.edit("no valid user_id / message specified") 75 | message_out_str = "" 76 | message_out_str += f"➾ First Name: {from_user.first_name}\n" 77 | last_name = from_user.last_name or "None" 78 | message_out_str += f"➾ Last Name: {last_name}\n" 79 | message_out_str += f"➾ Telegram ID: {from_user.id}\n" 80 | username = from_user.username or "None" 81 | dc_id = from_user.dc_id or "[User Doesnt Have A Valid DP]" 82 | message_out_str += f"➾ Data Centre: {dc_id}\n" 83 | message_out_str += f"➾ User Name: @{username}\n" 84 | message_out_str += f"➾ User 𝖫𝗂𝗇𝗄: Click Here\n" 85 | if message.chat.type in (("supergroup", "channel")): 86 | try: 87 | chat_member_p = await message.chat.get_member(from_user.id) 88 | joined_date = datetime.fromtimestamp( 89 | chat_member_p.joined_date or time.time() 90 | ).strftime("%Y.%m.%d %H:%M:%S") 91 | message_out_str += ( 92 | "➾ Joined this Chat on: " 93 | f"{joined_date}" 94 | "\n" 95 | ) 96 | except UserNotParticipant: 97 | pass 98 | chat_photo = from_user.photo 99 | if chat_photo: 100 | local_user_photo = await client.download_media( 101 | message=chat_photo.big_file_id 102 | ) 103 | buttons = [[ 104 | InlineKeyboardButton('🔐 𝗖𝗹𝗼𝘀𝗲 🔐', callback_data='close_data') 105 | ]] 106 | reply_markup = InlineKeyboardMarkup(buttons) 107 | await message.reply_photo( 108 | photo=local_user_photo, 109 | quote=True, 110 | reply_markup=reply_markup, 111 | caption=message_out_str, 112 | parse_mode="html", 113 | disable_notification=True 114 | ) 115 | os.remove(local_user_photo) 116 | else: 117 | buttons = [[ 118 | InlineKeyboardButton('🔐 𝗖𝗹𝗼𝘀𝗲 🔐', callback_data='close_data') 119 | ]] 120 | reply_markup = InlineKeyboardMarkup(buttons) 121 | await message.reply_text( 122 | text=message_out_str, 123 | reply_markup=reply_markup, 124 | quote=True, 125 | parse_mode="html", 126 | disable_notification=True 127 | ) 128 | await status_message.delete() 129 | 130 | @Client.on_message(filters.command(["imdb", 'search'])) 131 | async def imdb_search(client, message): 132 | if ' ' in message.text: 133 | k = await message.reply('Searching ImDB') 134 | r, title = message.text.split(None, 1) 135 | movies = await get_poster(title, bulk=True) 136 | if not movies: 137 | return await message.reply("No results Found") 138 | btn = [ 139 | [ 140 | InlineKeyboardButton( 141 | text=f"{movie.get('title')} - {movie.get('year')}", 142 | callback_data=f"imdb#{movie.movieID}", 143 | ) 144 | ] 145 | for movie in movies 146 | ] 147 | await k.edit('Here is what i found on IMDb', reply_markup=InlineKeyboardMarkup(btn)) 148 | else: 149 | await message.reply('Give me a movie / series Name') 150 | 151 | @Client.on_callback_query(filters.regex('^imdb')) 152 | async def imdb_callback(bot: Client, quer_y: CallbackQuery): 153 | i, movie = quer_y.data.split('#') 154 | imdb = await get_poster(query=movie, id=True) 155 | btn = [ 156 | [ 157 | InlineKeyboardButton( 158 | text=f"{imdb.get('title')}", 159 | url=imdb['url'], 160 | ) 161 | ] 162 | ] 163 | message = quer_y.message.reply_to_message or quer_y.message 164 | if imdb: 165 | caption = IMDB_TEMPLATE.format( 166 | query = imdb['title'], 167 | title = imdb['title'], 168 | votes = imdb['votes'], 169 | aka = imdb["aka"], 170 | seasons = imdb["seasons"], 171 | box_office = imdb['box_office'], 172 | localized_title = imdb['localized_title'], 173 | kind = imdb['kind'], 174 | imdb_id = imdb["imdb_id"], 175 | cast = imdb["cast"], 176 | runtime = imdb["runtime"], 177 | countries = imdb["countries"], 178 | certificates = imdb["certificates"], 179 | languages = imdb["languages"], 180 | director = imdb["director"], 181 | writer = imdb["writer"], 182 | producer = imdb["producer"], 183 | composer = imdb["composer"], 184 | cinematographer = imdb["cinematographer"], 185 | music_team = imdb["music_team"], 186 | distributors = imdb["distributors"], 187 | release_date = imdb['release_date'], 188 | year = imdb['year'], 189 | genres = imdb['genres'], 190 | poster = imdb['poster'], 191 | plot = imdb['plot'], 192 | rating = imdb['rating'], 193 | url = imdb['url'], 194 | **locals() 195 | ) 196 | else: 197 | caption = "No Results" 198 | if imdb.get('poster'): 199 | try: 200 | await quer_y.message.reply_photo(photo=imdb['poster'], caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 201 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty): 202 | pic = imdb.get('poster') 203 | poster = pic.replace('.jpg', "._V1_UX360.jpg") 204 | await quer_y.message.reply_photo(photo=poster, caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 205 | except Exception as e: 206 | logger.exception(e) 207 | await quer_y.message.reply(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 208 | await quer_y.message.delete() 209 | else: 210 | await quer_y.message.edit(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 211 | await quer_y.answer() 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /plugins/index.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import asyncio 3 | from pyrogram import Client, filters 4 | from pyrogram.errors import FloodWait 5 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, ChatAdminRequired, UsernameInvalid, UsernameNotModified 6 | from info import ADMINS, LOG_CHANNEL 7 | from database.ia_filterdb import save_file 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 9 | from utils import temp 10 | import re 11 | logger = logging.getLogger(__name__) 12 | logger.setLevel(logging.INFO) 13 | lock = asyncio.Lock() 14 | 15 | 16 | @Client.on_callback_query(filters.regex(r'^index')) 17 | async def index_files(bot, query): 18 | if query.data.startswith('index_cancel'): 19 | temp.CANCEL = True 20 | return await query.answer("Cancelling Indexing") 21 | _, raju, chat, lst_msg_id, from_user = query.data.split("#") 22 | if raju == 'reject': 23 | await query.message.delete() 24 | await bot.send_message(int(from_user), 25 | f'Your Submission for indexing {chat} has been decliened by our moderators.', 26 | reply_to_message_id=int(lst_msg_id)) 27 | return 28 | 29 | if lock.locked(): 30 | return await query.answer('Wait until previous process complete.', show_alert=True) 31 | msg = query.message 32 | 33 | await query.answer('𝗖𝗵𝗲𝗰𝗸𝗶𝗻𝗴...⏳😜', show_alert=True) 34 | if int(from_user) not in ADMINS: 35 | await bot.send_message(int(from_user), 36 | f'Your Submission for indexing {chat} has been accepted by our moderators and will be added soon.', 37 | reply_to_message_id=int(lst_msg_id)) 38 | await msg.edit( 39 | "Starting Indexing", 40 | reply_markup=InlineKeyboardMarkup( 41 | [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 42 | ) 43 | ) 44 | try: 45 | chat = int(chat) 46 | except: 47 | chat = chat 48 | await index_files_to_db(int(lst_msg_id), chat, msg, bot) 49 | 50 | 51 | @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) 52 | async def send_for_index(bot, message): 53 | if message.text: 54 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$") 55 | match = regex.match(message.text) 56 | if not match: 57 | return await message.reply('Invalid link') 58 | chat_id = match.group(4) 59 | last_msg_id = int(match.group(5)) 60 | if chat_id.isnumeric(): 61 | chat_id = int(("-100" + chat_id)) 62 | elif message.forward_from_chat.type == 'channel': 63 | last_msg_id = message.forward_from_message_id 64 | chat_id = message.forward_from_chat.username or message.forward_from_chat.id 65 | else: 66 | return 67 | try: 68 | await bot.get_chat(chat_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 | logger.exception(e) 75 | return await message.reply(f'Errors - {e}') 76 | try: 77 | k = await bot.get_messages(chat_id, last_msg_id) 78 | except: 79 | return await message.reply('Make Sure That Iam An Admin In The Channel, if channel is private') 80 | if k.empty: 81 | return await message.reply('This may be group and iam not a admin of the group.') 82 | 83 | if message.from_user.id in ADMINS: 84 | buttons = [ 85 | [ 86 | InlineKeyboardButton('𝗬𝗲𝘀', 87 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 88 | ], 89 | [ 90 | InlineKeyboardButton('𝗖𝗹𝗼𝘀𝗲', callback_data='close_data'), 91 | ] 92 | ] 93 | reply_markup = InlineKeyboardMarkup(buttons) 94 | return await message.reply( 95 | f'Do you Want To Index This Channel/ Group ?\n\nChat ID/ Username: {chat_id}\nLast Message ID: {last_msg_id}', 96 | reply_markup=reply_markup) 97 | 98 | if type(chat_id) is int: 99 | try: 100 | link = (await bot.create_chat_invite_link(chat_id)).invite_link 101 | except ChatAdminRequired: 102 | return await message.reply('Make sure iam an admin in the chat and have permission to invite users.') 103 | else: 104 | link = f"@{message.forward_from_chat.username}" 105 | buttons = [ 106 | [ 107 | InlineKeyboardButton('😍 𝗔𝗰𝗰𝗲𝗽𝘁 𝗜𝗻𝗱𝗲𝘅 😍', 108 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 109 | ], 110 | [ 111 | InlineKeyboardButton('😥 𝗥𝗲𝗷𝗲𝗰𝘁 𝗜𝗻𝗱𝗲𝘅 😥', 112 | callback_data=f'index#reject#{chat_id}#{message.message_id}#{message.from_user.id}'), 113 | ] 114 | ] 115 | reply_markup = InlineKeyboardMarkup(buttons) 116 | await bot.send_message(LOG_CHANNEL, 117 | 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}', 118 | reply_markup=reply_markup) 119 | await message.reply('ThankYou For the Contribution, Wait For My Moderators to verify the files.') 120 | 121 | 122 | @Client.on_message(filters.command('setskip') & filters.user(ADMINS)) 123 | async def set_skip_number(bot, message): 124 | if ' ' in message.text: 125 | _, skip = message.text.split(" ") 126 | try: 127 | skip = int(skip) 128 | except: 129 | return await message.reply("Skip number should be an integer.") 130 | await message.reply(f"Succesfully set SKIP number as {skip}") 131 | temp.CURRENT = int(skip) 132 | else: 133 | await message.reply("Give me a skip number") 134 | 135 | 136 | async def index_files_to_db(lst_msg_id, chat, msg, bot): 137 | total_files = 0 138 | duplicate = 0 139 | errors = 0 140 | deleted = 0 141 | no_media = 0 142 | async with lock: 143 | try: 144 | total = lst_msg_id + 1 145 | current = temp.CURRENT 146 | temp.CANCEL = False 147 | while current < total: 148 | if temp.CANCEL: 149 | await msg.edit("Succesfully Cancelled") 150 | break 151 | try: 152 | message = await bot.get_messages(chat_id=chat, message_ids=current, replies=0) 153 | except FloodWait as e: 154 | await asyncio.sleep(e.x) 155 | message = await bot.get_messages( 156 | chat, 157 | current, 158 | replies=0 159 | ) 160 | except Exception as e: 161 | logger.exception(e) 162 | try: 163 | for file_type in ("document", "video", "audio"): 164 | media = getattr(message, file_type, None) 165 | if media is not None: 166 | break 167 | else: 168 | continue 169 | media.file_type = file_type 170 | media.caption = message.caption 171 | aynav, vnay = await save_file(media) 172 | if aynav: 173 | total_files += 1 174 | elif vnay == 0: 175 | duplicate += 1 176 | elif vnay == 2: 177 | errors += 1 178 | except Exception as e: 179 | if "NoneType" in str(e): 180 | if message.empty: 181 | deleted += 1 182 | elif not media: 183 | no_media += 1 184 | logger.warning("Skipping deleted / Non-Media messages (if this continues for long, use /setskip to set a skip number)") 185 | else: 186 | logger.exception(e) 187 | current += 1 188 | if current % 20 == 0: 189 | can = [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 190 | reply = InlineKeyboardMarkup(can) 191 | await msg.edit_text( 192 | 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}\nErrors Occured: {errors}", 193 | reply_markup=reply) 194 | except Exception as e: 195 | logger.exception(e) 196 | await msg.edit(f'Error: {e}') 197 | else: 198 | await msg.edit(f'Succesfully saved {total_files} to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media}\nErrors Occured: {errors}') 199 | -------------------------------------------------------------------------------- /plugins/filters.py: -------------------------------------------------------------------------------- 1 | import io 2 | from pyrogram import filters, Client 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', 'add']) & 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 == "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 ["group", "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 != "administrator" 48 | and st.status != "creator" 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="md" 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 == "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 ["group", "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 != "administrator" 151 | and st.status != "creator" 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="md" 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 == "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 | 203 | elif chat_type in ["group", "supergroup"]: 204 | grp_id = message.chat.id 205 | title = message.chat.title 206 | 207 | else: 208 | return 209 | 210 | st = await client.get_chat_member(grp_id, userid) 211 | if ( 212 | st.status != "administrator" 213 | and st.status != "creator" 214 | and str(userid) not in ADMINS 215 | ): 216 | return 217 | 218 | try: 219 | cmd, text = message.text.split(" ", 1) 220 | except: 221 | await message.reply_text( 222 | "Mention the filtername which you wanna delete!\n\n" 223 | "/del filtername\n\n" 224 | "Use /viewfilters to view all available filters", 225 | quote=True 226 | ) 227 | return 228 | 229 | query = text.lower() 230 | 231 | await delete_filter(message, query, grp_id) 232 | 233 | 234 | @Client.on_message(filters.command('delall') & filters.incoming) 235 | async def delallconfirm(client, message): 236 | userid = message.from_user.id if message.from_user else None 237 | if not userid: 238 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 239 | chat_type = message.chat.type 240 | 241 | if chat_type == "private": 242 | grpid = await active_connection(str(userid)) 243 | if grpid is not None: 244 | grp_id = grpid 245 | try: 246 | chat = await client.get_chat(grpid) 247 | title = chat.title 248 | except: 249 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 250 | return 251 | else: 252 | await message.reply_text("I'm not connected to any groups!", quote=True) 253 | return 254 | 255 | elif chat_type in ["group", "supergroup"]: 256 | grp_id = message.chat.id 257 | title = message.chat.title 258 | 259 | else: 260 | return 261 | 262 | st = await client.get_chat_member(grp_id, userid) 263 | if (st.status == "creator") or (str(userid) in ADMINS): 264 | await message.reply_text( 265 | f"This will delete all filters from '{title}'.\nDo you want to continue??", 266 | reply_markup=InlineKeyboardMarkup([ 267 | [InlineKeyboardButton(text="YES",callback_data="delallconfirm")], 268 | [InlineKeyboardButton(text="CANCEL",callback_data="delallcancel")] 269 | ]), 270 | quote=True 271 | ) 272 | 273 | -------------------------------------------------------------------------------- /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 7 | from pyrogram.errors.exceptions.bad_request_400 import ChatAdminRequired 8 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 9 | from database.ia_filterdb import Media, get_file_details, unpack_new_file_id 10 | from database.users_chats_db import db 11 | from info import CHANNELS, ADMINS, AUTH_CHANNEL, CUSTOM_FILE_CAPTION, LOG_CHANNEL, PICS 12 | from utils import get_size, is_subscribed, temp 13 | import re 14 | logger = logging.getLogger(__name__) 15 | 16 | @Client.on_message(filters.command("start")) 17 | async def start(client, message): 18 | if message.chat.type in ['group', 'supergroup']: 19 | buttons = [ 20 | [ 21 | InlineKeyboardButton('𝙿𝚁𝙸𝚅𝙰𝚃𝙴 𝙱𝙾𝚃 ?', url=f"https://t.me/cyniteofficial") 22 | ] 23 | ] 24 | reply_markup = InlineKeyboardMarkup(buttons) 25 | await message.reply(script.PRIVATEBOT_TXT.format(message.from_user.mention if message.from_user else message.chat.title, temp.U_NAME, temp.B_NAME), reply_markup=reply_markup) 26 | await asyncio.sleep(2) # 😢 https://github.com/EvamariaTG/EvaMaria/blob/master/plugins/p_ttishow.py#L17 😬 wait a bit, before checking. 27 | if not await db.get_chat(message.chat.id): 28 | total=await client.get_chat_members_count(message.chat.id) 29 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, "Unknown")) 30 | await db.add_chat(message.chat.id, message.chat.title) 31 | return 32 | if not await db.is_user_exist(message.from_user.id): 33 | await db.add_user(message.from_user.id, message.from_user.first_name) 34 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_P.format(message.from_user.id, message.from_user.mention)) 35 | if len(message.command) != 2: 36 | buttons = [[ 37 | InlineKeyboardButton('⚚ ᴀᴅᴅ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ɢʀᴏᴜᴘ ⚚', url=f'http://t.me/{temp.U_NAME}?startgroup=true') 38 | ],[ 39 | InlineKeyboardButton('💠 ʙᴏᴛ ᴜᴘᴅᴀᴛᴇs 💠', url='https://t.me/Cynitebots'), 40 | InlineKeyboardButton('♻️ ʜᴇʟᴘ ♻️', callback_data='help')],[ 41 | InlineKeyboardButton('♻️ ᴀʙᴏᴜᴛ ♻️', callback_data='about'), 42 | InlineKeyboardButton('🔍sᴇᴀʀᴄʜ', switch_inline_query_current_chat=''), ]] 43 | await message.reply_photo( 44 | photo=random.choice(PICS), 45 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME), 46 | reply_markup=reply_markup, 47 | parse_mode='html' 48 | ) 49 | return 50 | if AUTH_CHANNEL and not await is_subscribed(client, message): 51 | try: 52 | invite_link = await client.create_chat_invite_link(int(AUTH_CHANNEL)) 53 | except ChatAdminRequired: 54 | logger.error("Make sure Bot is admin in Forcesub channel") 55 | return 56 | btn = [ 57 | [ 58 | InlineKeyboardButton( 59 | "🔥 JOIN CHANNEL 🔥", url=invite_link.invite_link 60 | ) 61 | ] 62 | ] 63 | 64 | if message.command[1] != "subscribe": 65 | btn.append([InlineKeyboardButton("🔁 𝐓𝐫𝐲 𝐀𝐠𝐚𝐢𝐧 🔁", callback_data=f"checksub#{message.command[1]}")]) 66 | await client.send_message( 67 | chat_id=message.from_user.id, 68 | text="**𝑱𝒐𝒊𝒏 𝑶𝒖𝒓 𝑴𝒐𝒗𝒊𝒆 𝑼𝒑𝒅𝒂𝒕𝒆𝒔 𝑪𝒉𝒂𝒏𝒏𝒆𝒍 𝑻𝒐 𝑼𝒔𝒆 𝑶𝒖𝒓 𝑩𝒐𝒕!**", 69 | reply_markup=InlineKeyboardMarkup(btn), 70 | parse_mode="markdown" 71 | ) 72 | return 73 | if len(message.command) ==2 and message.command[1] in ["subscribe", "error", "okay", "help"]: 74 | buttons = [[ 75 | InlineKeyboardButton('⚚ ᴀᴅᴅ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ɢʀᴏᴜᴘ ⚚', url=f'http://t.me/{temp.U_NAME}?startgroup=true') 76 | ],[ 77 | InlineKeyboardButton('💠 ʙᴏᴛ ᴜᴘᴅᴀᴛᴇs 💠', url='https://t.me/Cynitebots'), 78 | InlineKeyboardButton('♻️ ʜᴇʟᴘ ♻️', callback_data='help')],[ 79 | InlineKeyboardButton('♻️ ᴀʙᴏᴜᴛ ♻️', callback_data='about'), 80 | InlineKeyboardButton('🔍sᴇᴀʀᴄʜ', switch_inline_query_current_chat=''), ]] 81 | reply_markup = InlineKeyboardMarkup(buttons) 82 | await message.reply_photo( 83 | photo=random.choice(PICS), 84 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME), 85 | reply_markup=reply_markup, 86 | parse_mode='html' 87 | ) 88 | return 89 | file_id = message.command[1] 90 | files_ = await get_file_details(file_id) 91 | if not files_: 92 | return await message.reply('No such file exist.') 93 | files = files_[0] 94 | title = files.file_name 95 | size=get_size(files.file_size) 96 | f_caption=files.caption 97 | if CUSTOM_FILE_CAPTION: 98 | try: 99 | f_caption=CUSTOM_FILE_CAPTION.format(file_name=title, file_size=size, file_caption=f_caption) 100 | except Exception as e: 101 | logger.exception(e) 102 | f_caption=f_caption 103 | if f_caption is None: 104 | f_caption = f"{files.file_name}" 105 | await client.send_cached_media( 106 | chat_id=message.from_user.id, 107 | file_id=file_id, 108 | caption=f_caption, 109 | ) 110 | 111 | 112 | @Client.on_message(filters.command('channel') & filters.user(ADMINS)) 113 | async def channel_info(bot, message): 114 | 115 | """Send basic information of channel""" 116 | if isinstance(CHANNELS, (int, str)): 117 | channels = [CHANNELS] 118 | elif isinstance(CHANNELS, list): 119 | channels = CHANNELS 120 | else: 121 | raise ValueError("Unexpected type of CHANNELS") 122 | 123 | text = '📑 **Indexed channels/groups**\n' 124 | for channel in channels: 125 | chat = await bot.get_chat(channel) 126 | if chat.username: 127 | text += '\n@' + chat.username 128 | else: 129 | text += '\n' + chat.title or chat.first_name 130 | 131 | text += f'\n\n**Total:** {len(CHANNELS)}' 132 | 133 | if len(text) < 4096: 134 | await message.reply(text) 135 | else: 136 | file = 'Indexed channels.txt' 137 | with open(file, 'w') as f: 138 | f.write(text) 139 | await message.reply_document(file) 140 | os.remove(file) 141 | 142 | 143 | @Client.on_message(filters.command('logs') & filters.user(ADMINS)) 144 | async def log_file(bot, message): 145 | """Send log file""" 146 | try: 147 | await message.reply_document('TelegramBot.log') 148 | except Exception as e: 149 | await message.reply(str(e)) 150 | 151 | @Client.on_message(filters.command('delete') & filters.user(ADMINS)) 152 | async def delete(bot, message): 153 | """Delete file from database""" 154 | reply = message.reply_to_message 155 | if reply and reply.media: 156 | msg = await message.reply("𝗖𝗵𝗲𝗰𝗸𝗶𝗻𝗴...⏳😜", quote=True) 157 | else: 158 | await message.reply('Reply to file with /delete which you want to delete', quote=True) 159 | return 160 | 161 | for file_type in ("document", "video", "audio"): 162 | media = getattr(reply, file_type, None) 163 | if media is not None: 164 | break 165 | else: 166 | await msg.edit('This is not supported file format') 167 | return 168 | 169 | file_id, file_ref = unpack_new_file_id(media.file_id) 170 | 171 | result = await Media.collection.delete_one({ 172 | '_id': file_id, 173 | }) 174 | if result.deleted_count: 175 | await msg.edit('File is successfully deleted from database') 176 | else: 177 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 178 | result = await Media.collection.delete_one({ 179 | 'file_name': file_name, 180 | 'file_size': media.file_size, 181 | 'mime_type': media.mime_type 182 | }) 183 | if result.deleted_count: 184 | await msg.edit('File is successfully deleted from database') 185 | else: 186 | # files indexed before https://github.com/EvamariaTG/EvaMaria/commit/f3d2a1bcb155faf44178e5d7a685a1b533e714bf#diff-86b613edf1748372103e94cacff3b578b36b698ef9c16817bb98fe9ef22fb669R39 187 | # have original file name. 188 | result = await Media.collection.delete_one({ 189 | 'file_name': media.file_name, 190 | 'file_size': media.file_size, 191 | 'mime_type': media.mime_type 192 | }) 193 | if result.deleted_count: 194 | await msg.edit('File is successfully deleted from database') 195 | else: 196 | await msg.edit('File not found in database') 197 | 198 | 199 | @Client.on_message(filters.command('deleteall') & filters.user(ADMINS)) 200 | async def delete_all_index(bot, message): 201 | await message.reply_text( 202 | 'This will delete all indexed files.\nDo you want to continue??', 203 | reply_markup=InlineKeyboardMarkup( 204 | [ 205 | [ 206 | InlineKeyboardButton( 207 | text="𝗬𝗘𝗦😘", callback_data="autofilter_delete" 208 | ) 209 | ], 210 | [ 211 | InlineKeyboardButton( 212 | text="𝗖𝗔𝗡𝗖𝗘𝗟☹️", callback_data="close_data" 213 | ) 214 | ], 215 | ] 216 | ), 217 | quote=True, 218 | ) 219 | 220 | 221 | @Client.on_callback_query(filters.regex(r'^autofilter_delete')) 222 | async def delete_all_index_confirm(bot, message): 223 | await Media.collection.drop() 224 | await message.answer() 225 | await message.message.edit('Succesfully Deleted All The Indexed Files.') 226 | 227 | -------------------------------------------------------------------------------- /plugins/p_ttishow.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 3 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong, PeerIdInvalid 4 | from info import ADMINS, LOG_CHANNEL, SUPPORT_CHAT 5 | from database.users_chats_db import db 6 | from database.ia_filterdb import Media 7 | from utils import get_size, temp 8 | from Script import script 9 | from pyrogram.errors import ChatAdminRequired 10 | 11 | """-----------------------------------------https://t.me/GetTGLink/4179 --------------------------------------""" 12 | 13 | @Client.on_message(filters.new_chat_members & filters.group) 14 | async def save_group(bot, message): 15 | r_j_check = [u.id for u in message.new_chat_members] 16 | if temp.ME in r_j_check: 17 | if not await db.get_chat(message.chat.id): 18 | total=await bot.get_chat_members_count(message.chat.id) 19 | r_j = message.from_user.mention if message.from_user else "Anonymous" 20 | await bot.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, r_j)) 21 | await db.add_chat(message.chat.id, message.chat.title) 22 | if message.chat.id in temp.BANNED_CHATS: 23 | # Inspired from a boat of a banana tree 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\𝚗𝙼𝚈 𝙰𝙳𝙼𝙸𝙽𝚂 𝙷𝙰𝚂 𝚁𝙴𝚂𝚃𝚁𝙸𝙲𝚃𝙴𝙳 𝙼𝙴 𝙵𝚁𝙾𝙼 𝚆𝙾𝚁𝙺𝙸𝙽𝙶 𝙷𝙴𝚁𝙴 !𝙸𝙵 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝚃𝙾 𝙺𝙽𝙾𝚆 𝙼𝙾𝚁𝙴 𝙰𝙱𝙾𝚄𝚃 𝙸𝚃 𝙲𝙾𝙽𝚃𝙰𝙲𝚃 𝙾𝚆𝙽𝙴𝚁..', 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 | [ 41 | InlineKeyboardButton('💠 CHANNEL 💠', url='https://t.me/Imdb_updates') 42 | ], 43 | [ 44 | InlineKeyboardButton('♻️ HELP ♻️', url=f"https://t.me/{temp.U_NAME}?start=help") 45 | ] 46 | ] 47 | reply_markup=InlineKeyboardMarkup(buttons) 48 | await message.reply_text( 49 | text=f"Thankyou For Adding Me In {message.chat.title} ❣️\n\nIf You Have Any Questions & Doubts About Using Me Contact Owner ›› @BKC0001.", 50 | reply_markup=reply_markup) 51 | else: 52 | for u in message.new_chat_members: 53 | if (temp.MELCOW).get('welcome') is not None: 54 | try: 55 | await (temp.MELCOW['welcome']).delete() 56 | except: 57 | pass 58 | temp.MELCOW['welcome'] = await message.reply(f"𝙷𝙴𝚈 {u.mention}⚡ 𝚆𝙴𝙻𝙲𝙾𝙼𝙴 𝚃𝙾 {message.chat.title}!") 59 | 60 | 61 | @Client.on_message(filters.command('leave') & filters.user(ADMINS)) 62 | async def leave_a_chat(bot, message): 63 | if len(message.command) == 1: 64 | return await message.reply('Give 𝚖𝚎 𝚊 𝚌𝚑𝚊𝚝 id') 65 | chat = message.command[1] 66 | try: 67 | chat = int(chat) 68 | except: 69 | chat = chat 70 | try: 71 | buttons = [[ 72 | InlineKeyboardButton('𝗢𝗪𝗡𝗘𝗥', url=f'https://t.me/{SUPPORT_CHAT}') 73 | ]] 74 | reply_markup=InlineKeyboardMarkup(buttons) 75 | await bot.send_message( 76 | chat_id=chat, 77 | text='Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group.', 78 | reply_markup=reply_markup, 79 | ) 80 | 81 | await bot.leave_chat(chat) 82 | except Exception as e: 83 | await message.reply(f'Error - {e}') 84 | 85 | @Client.on_message(filters.command('disable') & filters.user(ADMINS)) 86 | async def disable_chat(bot, message): 87 | if len(message.command) == 1: 88 | return await message.reply('Give me a chat id') 89 | r = message.text.split(None) 90 | if len(r) > 2: 91 | reason = message.text.split(None, 2)[2] 92 | chat = message.text.split(None, 2)[1] 93 | else: 94 | chat = message.command[1] 95 | reason = "No reason Provided" 96 | try: 97 | chat_ = int(chat) 98 | except: 99 | return await message.reply('Give Me A Valid Chat ID') 100 | cha_t = await db.get_chat(int(chat_)) 101 | if not cha_t: 102 | return await message.reply("Chat Not Found In DB") 103 | if cha_t['is_disabled']: 104 | return await message.reply(f"This chat is already disabled:\nReason- {cha_t['reason']} ") 105 | await db.disable_chat(int(chat_), reason) 106 | temp.BANNED_CHATS.append(int(chat_)) 107 | await message.reply('Chat Succesfully Disabled') 108 | try: 109 | buttons = [[ 110 | InlineKeyboardButton('𝗢𝗪𝗡𝗘𝗥', url=f'https://t.me/{SUPPORT_CHAT}') 111 | ]] 112 | reply_markup=InlineKeyboardMarkup(buttons) 113 | await bot.send_message( 114 | chat_id=chat_, 115 | text=f'Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group. \nReason : {reason}', 116 | reply_markup=reply_markup) 117 | await bot.leave_chat(chat_) 118 | except Exception as e: 119 | await message.reply(f"Error - {e}") 120 | 121 | 122 | @Client.on_message(filters.command('enable') & filters.user(ADMINS)) 123 | async def re_enable_chat(bot, message): 124 | if len(message.command) == 1: 125 | return await message.reply('Give me a chat id') 126 | chat = message.command[1] 127 | try: 128 | chat_ = int(chat) 129 | except: 130 | return await message.reply('Give Me A Valid Chat ID') 131 | sts = await db.get_chat(int(chat)) 132 | if not sts: 133 | return await message.reply("Chat Not Found In DB !") 134 | if not sts.get('is_disabled'): 135 | return await message.reply('This chat is not yet disabled.') 136 | await db.re_enable_chat(int(chat_)) 137 | temp.BANNED_CHATS.remove(int(chat_)) 138 | await message.reply("Chat Succesfully re-enabled") 139 | 140 | 141 | @Client.on_message(filters.command('stats') & filters.user(ADMINS)) 142 | async def get_ststs(bot, message): 143 | rju = await message.reply('𝙰𝙲𝙲𝙴𝚂𝚂𝙸𝙽𝙶 𝚂𝚃𝙰𝚃𝚄𝚂 𝙳𝙴𝚃𝙰𝙸𝙻𝚂...') 144 | total_users = await db.total_users_count() 145 | totl_chats = await db.total_chat_count() 146 | files = await Media.count_documents() 147 | size = await db.get_db_size() 148 | free = 536870912 - size 149 | size = get_size(size) 150 | free = get_size(free) 151 | await rju.edit(script.STATUS_TXT.format(files, total_users, totl_chats, size, free)) 152 | 153 | 154 | # a function for trespassing into others groups, Inspired by a Vazha 155 | # Not to be used , But Just to showcase his vazhatharam. 156 | # @Client.on_message(filters.command('invite') & filters.user(ADMINS)) 157 | async def gen_invite(bot, message): 158 | if len(message.command) == 1: 159 | return await message.reply('Give me a chat id') 160 | chat = message.command[1] 161 | try: 162 | chat = int(chat) 163 | except: 164 | return await message.reply('Give Me A Valid Chat ID') 165 | try: 166 | link = await bot.create_chat_invite_link(chat) 167 | except ChatAdminRequired: 168 | return await message.reply("Invite Link Generation Failed, Iam Not Having Sufficient Rights") 169 | except Exception as e: 170 | return await message.reply(f'Error {e}') 171 | await message.reply(f'Here is your Invite Link {link.invite_link}') 172 | 173 | @Client.on_message(filters.command('ban') & filters.user(ADMINS)) 174 | async def ban_a_user(bot, message): 175 | # https://t.me/GetTGLink/4185 176 | if len(message.command) == 1: 177 | return await message.reply('Give me a user id / username') 178 | r = message.text.split(None) 179 | if len(r) > 2: 180 | reason = message.text.split(None, 2)[2] 181 | chat = message.text.split(None, 2)[1] 182 | else: 183 | chat = message.command[1] 184 | reason = "No reason Provided" 185 | try: 186 | chat = int(chat) 187 | except: 188 | pass 189 | try: 190 | k = await bot.get_users(chat) 191 | except PeerIdInvalid: 192 | return await message.reply("This is an invalid user, make sure ia have met him before.") 193 | except IndexError: 194 | return await message.reply("This might be a channel, make sure its a user.") 195 | except Exception as e: 196 | return await message.reply(f'Error - {e}') 197 | else: 198 | jar = await db.get_ban_status(k.id) 199 | if jar['is_banned']: 200 | return await message.reply(f"{k.mention} is already banned\nReason: {jar['ban_reason']}") 201 | await db.ban_user(k.id, reason) 202 | temp.BANNED_USERS.append(k.id) 203 | await message.reply(f"Succesfully banned {k.mention}") 204 | 205 | 206 | 207 | @Client.on_message(filters.command('unban') & filters.user(ADMINS)) 208 | async def unban_a_user(bot, message): 209 | if len(message.command) == 1: 210 | return await message.reply('Give me a user id / username') 211 | r = message.text.split(None) 212 | if len(r) > 2: 213 | reason = message.text.split(None, 2)[2] 214 | chat = message.text.split(None, 2)[1] 215 | else: 216 | chat = message.command[1] 217 | reason = "No reason Provided" 218 | try: 219 | chat = int(chat) 220 | except: 221 | pass 222 | try: 223 | k = await bot.get_users(chat) 224 | except PeerIdInvalid: 225 | return await message.reply("This is an invalid user, make sure ia have met him before.") 226 | except IndexError: 227 | return await message.reply("Thismight be a channel, make sure its a user.") 228 | except Exception as e: 229 | return await message.reply(f'Error - {e}') 230 | else: 231 | jar = await db.get_ban_status(k.id) 232 | if not jar['is_banned']: 233 | return await message.reply(f"{k.mention} is not yet banned.") 234 | await db.remove_ban(k.id) 235 | temp.BANNED_USERS.remove(k.id) 236 | await message.reply(f"Succesfully unbanned {k.mention}") 237 | 238 | 239 | 240 | @Client.on_message(filters.command('users') & filters.user(ADMINS)) 241 | async def list_users(bot, message): 242 | # https://t.me/GetTGLink/4184 243 | raju = await message.reply('Getting List Of Users') 244 | users = await db.get_all_users() 245 | out = "Users Saved In DB Are:\n\n" 246 | async for user in users: 247 | out += f"{user['name']}\n" 248 | try: 249 | await raju.edit_text(out) 250 | except MessageTooLong: 251 | with open('users.txt', 'w+') as outfile: 252 | outfile.write(out) 253 | await message.reply_document('users.txt', caption="List Of Users") 254 | 255 | @Client.on_message(filters.command('chats') & filters.user(ADMINS)) 256 | async def list_chats(bot, message): 257 | raju = await message.reply('Getting List Of chats') 258 | chats = await db.get_all_chats() 259 | out = "Chats Saved In DB Are:\n\n" 260 | async for chat in chats: 261 | out += f"**Title:** `{chat['title']}`\n**- ID:** `{chat['id']}`\n" 262 | try: 263 | await raju.edit_text(out) 264 | except MessageTooLong: 265 | with open('chats.txt', 'w+') as outfile: 266 | outfile.write(out) 267 | await message.reply_document('chats.txt', caption="List Of Chats") 268 | -------------------------------------------------------------------------------- /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 4 | from imdb import IMDb 5 | import asyncio 6 | from pyrogram.types import Message 7 | from typing import Union 8 | import re 9 | import os 10 | from datetime import datetime 11 | from typing import List 12 | from pyrogram.types import InlineKeyboardButton 13 | from database.users_chats_db import db 14 | from bs4 import BeautifulSoup 15 | import requests 16 | 17 | logger = logging.getLogger(__name__) 18 | logger.setLevel(logging.INFO) 19 | 20 | BTN_URL_REGEX = re.compile( 21 | r"(\[([^\[]+?)\]\((buttonurl|buttonalert):(?:/{0,2})(.+?)(:same)?\))" 22 | ) 23 | 24 | imdb = IMDb() 25 | 26 | BANNED = {} 27 | SMART_OPEN = '“' 28 | SMART_CLOSE = '”' 29 | START_CHAR = ('\'', '"', SMART_OPEN) 30 | 31 | # temp db for banned 32 | class temp(object): 33 | BANNED_USERS = [] 34 | BANNED_CHATS = [] 35 | ME = None 36 | CURRENT=int(os.environ.get("SKIP", 2)) 37 | CANCEL = False 38 | MELCOW = {} 39 | U_NAME = None 40 | B_NAME = None 41 | 42 | async def is_subscribed(bot, query): 43 | try: 44 | user = await bot.get_chat_member(AUTH_CHANNEL, query.from_user.id) 45 | except UserNotParticipant: 46 | pass 47 | except Exception as e: 48 | logger.exception(e) 49 | else: 50 | if user.status != 'kicked': 51 | return True 52 | 53 | return False 54 | 55 | async def get_poster(query, bulk=False, id=False, file=None): 56 | if not id: 57 | # https://t.me/GetTGLink/4183 58 | query = (query.strip()).lower() 59 | title = query 60 | year = re.findall(r'[1-2]\d{3}$', query, re.IGNORECASE) 61 | if year: 62 | year = list_to_str(year[:1]) 63 | title = (query.replace(year, "")).strip() 64 | elif file is not None: 65 | year = re.findall(r'[1-2]\d{3}', file, re.IGNORECASE) 66 | if year: 67 | year = list_to_str(year[:1]) 68 | else: 69 | year = None 70 | movieid = imdb.search_movie(title.lower(), results=10) 71 | if not movieid: 72 | return None 73 | if year: 74 | filtered=list(filter(lambda k: str(k.get('year')) == str(year), movieid)) 75 | if not filtered: 76 | filtered = movieid 77 | else: 78 | filtered = movieid 79 | movieid=list(filter(lambda k: k.get('kind') in ['movie', 'tv series'], filtered)) 80 | if not movieid: 81 | movieid = filtered 82 | if bulk: 83 | return movieid 84 | movieid = movieid[0].movieID 85 | else: 86 | movieid = int(query) 87 | movie = imdb.get_movie(movieid) 88 | if movie.get("original air date"): 89 | date = movie["original air date"] 90 | elif movie.get("year"): 91 | date = movie.get("year") 92 | else: 93 | date = "N/A" 94 | plot = "" 95 | if not LONG_IMDB_DESCRIPTION: 96 | plot = movie.get('plot') 97 | if plot and len(plot) > 0: 98 | plot = plot[0] 99 | else: 100 | plot = movie.get('plot outline') 101 | if plot and len(plot) > 800: 102 | plot = plot[0:800] + "..." 103 | 104 | return { 105 | 'title': movie.get('title'), 106 | 'votes': movie.get('votes'), 107 | "aka": list_to_str(movie.get("akas")), 108 | "seasons": movie.get("number of seasons"), 109 | "box_office": movie.get('box office'), 110 | 'localized_title': movie.get('localized title'), 111 | 'kind': movie.get("kind"), 112 | "imdb_id": f"tt{movie.get('imdbID')}", 113 | "cast": list_to_str(movie.get("cast")), 114 | "runtime": list_to_str(movie.get("runtimes")), 115 | "countries": list_to_str(movie.get("countries")), 116 | "certificates": list_to_str(movie.get("certificates")), 117 | "languages": list_to_str(movie.get("languages")), 118 | "director": list_to_str(movie.get("director")), 119 | "writer":list_to_str(movie.get("writer")), 120 | "producer":list_to_str(movie.get("producer")), 121 | "composer":list_to_str(movie.get("composer")) , 122 | "cinematographer":list_to_str(movie.get("cinematographer")), 123 | "music_team": list_to_str(movie.get("music department")), 124 | "distributors": list_to_str(movie.get("distributors")), 125 | 'release_date': date, 126 | 'year': movie.get('year'), 127 | 'genres': list_to_str(movie.get("genres")), 128 | 'poster': movie.get('full-size cover url'), 129 | 'plot': plot, 130 | 'rating': str(movie.get("rating")), 131 | 'url':f'https://www.imdb.com/title/tt{movieid}' 132 | } 133 | # https://github.com/odysseusmax/animated-lamp/blob/2ef4730eb2b5f0596ed6d03e7b05243d93e3415b/bot/utils/broadcast.py#L37 134 | 135 | async def broadcast_messages(user_id, message): 136 | try: 137 | await message.copy(chat_id=user_id) 138 | return True, "Succes" 139 | except FloodWait as e: 140 | await asyncio.sleep(e.x) 141 | return await broadcast_messages(user_id, message) 142 | except InputUserDeactivated: 143 | await db.delete_user(int(user_id)) 144 | logging.info(f"{user_id}-Removed from Database, since deleted account.") 145 | return False, "Deleted" 146 | except UserIsBlocked: 147 | logging.info(f"{user_id} -Blocked the bot.") 148 | return False, "Blocked" 149 | except PeerIdInvalid: 150 | await db.delete_user(int(user_id)) 151 | logging.info(f"{user_id} - PeerIdInvalid") 152 | return False, "Error" 153 | except Exception as e: 154 | return False, "Error" 155 | 156 | async def search_gagala(text): 157 | usr_agent = { 158 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 159 | 'Chrome/61.0.3163.100 Safari/537.36' 160 | } 161 | text = text.replace(" ", '+') 162 | url = f'https://www.google.com/search?q={text}' 163 | response = requests.get(url, headers=usr_agent) 164 | response.raise_for_status() 165 | soup = BeautifulSoup(response.text, 'html.parser') 166 | titles = soup.find_all( 'h3' ) 167 | return [title.getText() for title in titles] 168 | 169 | 170 | 171 | 172 | def get_size(size): 173 | """Get size in readable format""" 174 | 175 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"] 176 | size = float(size) 177 | i = 0 178 | while size >= 1024.0 and i < len(units): 179 | i += 1 180 | size /= 1024.0 181 | return "%.2f %s" % (size, units[i]) 182 | 183 | def split_list(l, n): 184 | for i in range(0, len(l), n): 185 | yield l[i:i + n] 186 | 187 | def get_file_id(msg: Message): 188 | if msg.media: 189 | for message_type in ( 190 | "photo", 191 | "animation", 192 | "audio", 193 | "document", 194 | "video", 195 | "video_note", 196 | "voice", 197 | "sticker" 198 | ): 199 | obj = getattr(msg, message_type) 200 | if obj: 201 | setattr(obj, "message_type", message_type) 202 | return obj 203 | 204 | def extract_user(message: Message) -> Union[int, str]: 205 | """extracts the user from a message""" 206 | # https://github.com/SpEcHiDe/PyroGramBot/blob/f30e2cca12002121bad1982f68cd0ff9814ce027/pyrobot/helper_functions/extract_user.py#L7 207 | user_id = None 208 | user_first_name = None 209 | if message.reply_to_message: 210 | user_id = message.reply_to_message.from_user.id 211 | user_first_name = message.reply_to_message.from_user.first_name 212 | 213 | elif len(message.command) > 1: 214 | if ( 215 | len(message.entities) > 1 and 216 | message.entities[1].type == "text_mention" 217 | ): 218 | 219 | required_entity = message.entities[1] 220 | user_id = required_entity.user.id 221 | user_first_name = required_entity.user.first_name 222 | else: 223 | user_id = message.command[1] 224 | # don't want to make a request -_- 225 | user_first_name = user_id 226 | try: 227 | user_id = int(user_id) 228 | except ValueError: 229 | pass 230 | else: 231 | user_id = message.from_user.id 232 | user_first_name = message.from_user.first_name 233 | return (user_id, user_first_name) 234 | 235 | def list_to_str(k): 236 | if not k: 237 | return "N/A" 238 | elif len(k) == 1: 239 | return str(k[0]) 240 | elif MAX_LIST_ELM: 241 | k = k[:int(MAX_LIST_ELM)] 242 | return ' '.join(f'{elem}, ' for elem in k) 243 | else: 244 | return ' '.join(f'{elem}, ' for elem in k) 245 | 246 | def last_online(from_user): 247 | time = "" 248 | if from_user.is_bot: 249 | time += "🤖 Bot :(" 250 | elif from_user.status == 'recently': 251 | time += "Recently" 252 | elif from_user.status == 'within_week': 253 | time += "Within the last week" 254 | elif from_user.status == 'within_month': 255 | time += "Within the last month" 256 | elif from_user.status == 'long_time_ago': 257 | time += "A long time ago :(" 258 | elif from_user.status == 'online': 259 | time += "Currently Online" 260 | elif from_user.status == 'offline': 261 | time += datetime.fromtimestamp(from_user.last_online_date).strftime("%a, %d %b %Y, %H:%M:%S") 262 | return time 263 | 264 | 265 | def split_quotes(text: str) -> List: 266 | if not any(text.startswith(char) for char in START_CHAR): 267 | return text.split(None, 1) 268 | counter = 1 # ignore first char -> is some kind of quote 269 | while counter < len(text): 270 | if text[counter] == "\\": 271 | counter += 1 272 | elif text[counter] == text[0] or (text[0] == SMART_OPEN and text[counter] == SMART_CLOSE): 273 | break 274 | counter += 1 275 | else: 276 | return text.split(None, 1) 277 | 278 | # 1 to avoid starting quote, and counter is exclusive so avoids ending 279 | key = remove_escapes(text[1:counter].strip()) 280 | # index will be in range, or `else` would have been executed and returned 281 | rest = text[counter + 1:].strip() 282 | if not key: 283 | key = text[0] + text[0] 284 | return list(filter(None, [key, rest])) 285 | 286 | def parser(text, keyword): 287 | if "buttonalert" in text: 288 | text = (text.replace("\n", "\\n").replace("\t", "\\t")) 289 | buttons = [] 290 | note_data = "" 291 | prev = 0 292 | i = 0 293 | alerts = [] 294 | for match in BTN_URL_REGEX.finditer(text): 295 | # Check if btnurl is escaped 296 | n_escapes = 0 297 | to_check = match.start(1) - 1 298 | while to_check > 0 and text[to_check] == "\\": 299 | n_escapes += 1 300 | to_check -= 1 301 | 302 | # if even, not escaped -> create button 303 | if n_escapes % 2 == 0: 304 | note_data += text[prev:match.start(1)] 305 | prev = match.end(1) 306 | if match.group(3) == "buttonalert": 307 | # create a thruple with button label, url, and newline status 308 | if bool(match.group(5)) and buttons: 309 | buttons[-1].append(InlineKeyboardButton( 310 | text=match.group(2), 311 | callback_data=f"alertmessage:{i}:{keyword}" 312 | )) 313 | else: 314 | buttons.append([InlineKeyboardButton( 315 | text=match.group(2), 316 | callback_data=f"alertmessage:{i}:{keyword}" 317 | )]) 318 | i += 1 319 | alerts.append(match.group(4)) 320 | elif bool(match.group(5)) and buttons: 321 | buttons[-1].append(InlineKeyboardButton( 322 | text=match.group(2), 323 | url=match.group(4).replace(" ", "") 324 | )) 325 | else: 326 | buttons.append([InlineKeyboardButton( 327 | text=match.group(2), 328 | url=match.group(4).replace(" ", "") 329 | )]) 330 | 331 | else: 332 | note_data += text[prev:to_check] 333 | prev = match.start(1) - 1 334 | else: 335 | note_data += text[prev:] 336 | 337 | try: 338 | return note_data, buttons, alerts 339 | except: 340 | return note_data, buttons, None 341 | 342 | def remove_escapes(text: str) -> str: 343 | res = "" 344 | is_escaped = False 345 | for counter in range(len(text)): 346 | if is_escaped: 347 | res += text[counter] 348 | is_escaped = False 349 | elif text[counter] == "\\": 350 | is_escaped = True 351 | else: 352 | res += text[counter] 353 | return res 354 | 355 | 356 | def humanbytes(size): 357 | if not size: 358 | return "" 359 | power = 2**10 360 | n = 0 361 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'} 362 | while size > power: 363 | size /= power 364 | n += 1 365 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B' 366 | -------------------------------------------------------------------------------- /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/pm_filter.py: -------------------------------------------------------------------------------- 1 | #Kanged From @TroJanZheX 2 | import asyncio 3 | import re 4 | import ast 5 | 6 | from pyrogram.errors.exceptions.bad_request_400 import MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty 7 | from Script import script 8 | import pyrogram 9 | from database.connections_mdb import active_connection, all_connections, delete_connection, if_active, make_active, make_inactive 10 | from info import ADMINS, AUTH_CHANNEL, AUTH_USERS, CUSTOM_FILE_CAPTION, AUTH_GROUPS, P_TTI_SHOW_OFF, IMDB, SINGLE_BUTTON, SPELL_CHECK_REPLY, IMDB_TEMPLATE 11 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 12 | from pyrogram import Client, filters 13 | from pyrogram.errors import FloodWait, UserIsBlocked, MessageNotModified, PeerIdInvalid 14 | from utils import get_size, is_subscribed, get_poster, search_gagala, temp 15 | from database.users_chats_db import db 16 | from database.ia_filterdb import Media, get_file_details, get_search_results 17 | from database.filters_mdb import( 18 | del_all, 19 | find_filter, 20 | get_filters, 21 | ) 22 | import logging 23 | logger = logging.getLogger(__name__) 24 | logger.setLevel(logging.ERROR) 25 | 26 | BUTTONS = {} 27 | SPELL_CHECK = {} 28 | 29 | @Client.on_message(filters.text & ~filters.edited & filters.incoming) 30 | async def give_filter(client,message): 31 | k = await manual_filters(client, message) 32 | if k == False: 33 | await auto_filter(client, message) 34 | 35 | @Client.on_callback_query(filters.regex(r"^next")) 36 | async def next_page(bot, query): 37 | 38 | ident, req, key, offset = query.data.split("_") 39 | if int(req) not in [query.from_user.id, 0]: 40 | return await query.answer("😁 𝗛𝗲𝘆 𝗙𝗿𝗶𝗲𝗻𝗱,𝗣𝗹𝗲𝗮𝘀𝗲 𝗦𝗲𝗮𝗿𝗰𝗵 𝗬𝗼𝘂𝗿𝘀𝗲𝗹𝗳.", show_alert=True) 41 | try: 42 | offset = int(offset) 43 | except: 44 | offset = 0 45 | search = BUTTONS.get(key) 46 | if not search: 47 | await query.answer("𝐋𝐢𝐧𝐤 𝐄𝐱𝐩𝐢𝐫𝐞𝐝 𝐊𝐢𝐧𝐝𝐥𝐲 𝐏𝐥𝐞𝐚𝐬𝐞 𝐒𝐞𝐚𝐫𝐜𝐡 𝐀𝐠𝐚𝐢𝐧 🙂.",show_alert=True) 48 | return 49 | 50 | files, n_offset, total = await get_search_results(search, offset=offset, filter=True) 51 | try: 52 | n_offset = int(n_offset) 53 | except: 54 | n_offset = 0 55 | 56 | if not files: 57 | return 58 | if SINGLE_BUTTON: 59 | btn = [ 60 | [ 61 | InlineKeyboardButton( 62 | text=f"[{get_size(file.file_size)}] {file.file_name}", callback_data=f'files#{file.file_id}' 63 | ), 64 | ] 65 | for file in files 66 | ] 67 | else: 68 | btn = [ 69 | [ 70 | InlineKeyboardButton( 71 | text=f"{file.file_name}", callback_data=f'files#{file.file_id}' 72 | ), 73 | InlineKeyboardButton( 74 | text=f"{get_size(file.file_size)}", 75 | callback_data=f'files_#{file.file_id}', 76 | ), 77 | ] 78 | for file in files 79 | ] 80 | 81 | if 0 < offset <= 10: 82 | off_set = 0 83 | elif offset == 0: 84 | off_set = None 85 | else: 86 | off_set = offset - 10 87 | if n_offset == 0: 88 | btn.append( 89 | [InlineKeyboardButton("⬅️ 𝗕𝗮𝗰𝗸", callback_data=f"next_{req}_{key}_{off_set}"), InlineKeyboardButton(f"🌹 𝗣𝗮𝗴𝗲 {round(int(offset)/10)+1} / {round(total/10)}", callback_data="pages")] 90 | ) 91 | elif off_set is None: 92 | btn.append([InlineKeyboardButton(f"🌹 𝗣𝗮𝗴𝗲 {round(int(offset)/10)+1} / {round(total/10)}", callback_data="pages"), InlineKeyboardButton("𝗡𝗲𝘅𝘁 ➡️", callback_data=f"next_{req}_{key}_{n_offset}")]) 93 | else: 94 | btn.append( 95 | [ 96 | InlineKeyboardButton("⬅️ 𝗕𝗮𝗰𝗸", callback_data=f"next_{req}_{key}_{off_set}"), 97 | InlineKeyboardButton(f"🌹 𝗣𝗮𝗴𝗲 {round(int(offset)/10)+1} / {round(total/10)}", callback_data="pages"), 98 | InlineKeyboardButton("𝗡𝗲𝘅𝘁 ➡️", callback_data=f"next_{req}_{key}_{n_offset}") 99 | ], 100 | ) 101 | try: 102 | await query.edit_message_reply_markup( 103 | reply_markup=InlineKeyboardMarkup(btn) 104 | ) 105 | except MessageNotModified: 106 | pass 107 | await query.answer() 108 | 109 | @Client.on_callback_query(filters.regex(r"^spolling")) 110 | async def advantage_spoll_choker(bot, query): 111 | _, user, movie_ = query.data.split('#') 112 | if int(user) != 0 and query.from_user.id != int(user): 113 | return await query.answer("😁 𝗛𝗲𝘆 𝗙𝗿𝗶𝗲𝗻𝗱,𝗣𝗹𝗲𝗮𝘀𝗲 𝗦𝗲𝗮𝗿𝗰𝗵 𝗬𝗼𝘂𝗿𝘀𝗲𝗹𝗳.", show_alert=True) 114 | if movie_ == "close_spellcheck": 115 | return await query.message.delete() 116 | movies = SPELL_CHECK.get(query.message.reply_to_message.message_id) 117 | if not movies: 118 | return await query.answer("𝐋𝐢𝐧𝐤 𝐄𝐱𝐩𝐢𝐫𝐞𝐝 𝐊𝐢𝐧𝐝𝐥𝐲 𝐏𝐥𝐞𝐚𝐬𝐞 𝐒𝐞𝐚𝐫𝐜𝐡 𝐀𝐠𝐚𝐢𝐧 🙂.", show_alert=True) 119 | movie = movies[(int(movie_))] 120 | await query.answer('Checking For Movie In Database...') 121 | k = await manual_filters(bot, query.message, text=movie) 122 | if k==False: 123 | files, offset, total_results = await get_search_results(movie, offset=0, filter=True) 124 | if files: 125 | k = (movie, files, offset, total_results) 126 | await auto_filter(bot, query, k) 127 | else: 128 | k = await query.message.edit('𝚃𝙷𝙸𝚂 𝙼𝙾𝚅𝙸𝙴 I𝚂 𝙽𝙾𝚃 𝚈𝙴𝚃 𝚁𝙴𝙻𝙴𝙰𝚂𝙴𝙳 𝙾𝚁 𝙰𝙳𝙳𝙴𝙳 𝚃𝙾 𝙳𝙰𝚃𝚂𝙱𝙰𝚂𝙴💌') 129 | await asyncio.sleep(10) 130 | await k.delete() 131 | 132 | 133 | @Client.on_callback_query() 134 | async def cb_handler(client: Client, query: CallbackQuery): 135 | if query.data == "close_data": 136 | await query.message.delete() 137 | elif query.data == "delallconfirm": 138 | userid = query.from_user.id 139 | chat_type = query.message.chat.type 140 | 141 | if chat_type == "private": 142 | grpid = await active_connection(str(userid)) 143 | if grpid is not None: 144 | grp_id = grpid 145 | try: 146 | chat = await client.get_chat(grpid) 147 | title = chat.title 148 | except: 149 | await query.message.edit_text("Make sure I'm present in your group!!", quote=True) 150 | return 151 | else: 152 | await query.message.edit_text( 153 | "I'm not connected to any groups!\nCheck /connections or connect to any groups", 154 | quote=True 155 | ) 156 | return 157 | 158 | elif chat_type in ["group", "supergroup"]: 159 | grp_id = query.message.chat.id 160 | title = query.message.chat.title 161 | 162 | else: 163 | return 164 | 165 | st = await client.get_chat_member(grp_id, userid) 166 | if (st.status == "creator") or (str(userid) in ADMINS): 167 | await del_all(query.message, grp_id, title) 168 | else: 169 | await query.answer("You need to be Group Owner or an Auth User to do that!",show_alert=True) 170 | 171 | elif query.data == "delallcancel": 172 | userid = query.from_user.id 173 | chat_type = query.message.chat.type 174 | 175 | if chat_type == "private": 176 | await query.message.reply_to_message.delete() 177 | await query.message.delete() 178 | 179 | elif chat_type in ["group", "supergroup"]: 180 | grp_id = query.message.chat.id 181 | st = await client.get_chat_member(grp_id, userid) 182 | if (st.status == "creator") or (str(userid) in ADMINS): 183 | await query.message.delete() 184 | try: 185 | await query.message.reply_to_message.delete() 186 | except: 187 | pass 188 | else: 189 | await query.answer("Thats not for you!!",show_alert=True) 190 | 191 | 192 | elif "groupcb" in query.data: 193 | await query.answer() 194 | 195 | group_id = query.data.split(":")[1] 196 | 197 | act = query.data.split(":")[2] 198 | hr = await client.get_chat(int(group_id)) 199 | title = hr.title 200 | user_id = query.from_user.id 201 | 202 | if act == "": 203 | stat = "CONNECT" 204 | cb = "connectcb" 205 | else: 206 | stat = "DISCONNECT" 207 | cb = "disconnect" 208 | 209 | keyboard = InlineKeyboardMarkup([ 210 | [InlineKeyboardButton(f"{stat}", callback_data=f"{cb}:{group_id}"), 211 | InlineKeyboardButton("DELETE", callback_data=f"deletecb:{group_id}")], 212 | [InlineKeyboardButton("BACK", callback_data="backcb")] 213 | ]) 214 | 215 | await query.message.edit_text( 216 | f"Group Name : **{title}**\nGroup ID : `{group_id}`", 217 | reply_markup=keyboard, 218 | parse_mode="md" 219 | ) 220 | return 221 | 222 | elif "connectcb" in query.data: 223 | await query.answer() 224 | 225 | group_id = query.data.split(":")[1] 226 | 227 | hr = await client.get_chat(int(group_id)) 228 | 229 | title = hr.title 230 | 231 | user_id = query.from_user.id 232 | 233 | mkact = await make_active(str(user_id), str(group_id)) 234 | 235 | if mkact: 236 | await query.message.edit_text( 237 | f"Connected to **{title}**", 238 | parse_mode="md" 239 | ) 240 | else: 241 | await query.message.edit_text('Some error occured!!', parse_mode="md") 242 | return 243 | 244 | elif "disconnect" in query.data: 245 | await query.answer() 246 | 247 | group_id = query.data.split(":")[1] 248 | 249 | hr = await client.get_chat(int(group_id)) 250 | 251 | title = hr.title 252 | user_id = query.from_user.id 253 | 254 | mkinact = await make_inactive(str(user_id)) 255 | 256 | if mkinact: 257 | await query.message.edit_text( 258 | f"Disconnected from **{title}**", 259 | parse_mode="md" 260 | ) 261 | else: 262 | await query.message.edit_text( 263 | f"Some error occured!!", 264 | parse_mode="md" 265 | ) 266 | return 267 | elif "deletecb" in query.data: 268 | await query.answer() 269 | 270 | user_id = query.from_user.id 271 | group_id = query.data.split(":")[1] 272 | 273 | delcon = await delete_connection(str(user_id), str(group_id)) 274 | 275 | if delcon: 276 | await query.message.edit_text( 277 | "Successfully deleted connection" 278 | ) 279 | else: 280 | await query.message.edit_text( 281 | f"Some error occured!!", 282 | parse_mode="md" 283 | ) 284 | return 285 | elif query.data == "backcb": 286 | await query.answer() 287 | 288 | userid = query.from_user.id 289 | 290 | groupids = await all_connections(str(userid)) 291 | if groupids is None: 292 | await query.message.edit_text( 293 | "There are no active connections!! Connect to some groups first.", 294 | ) 295 | return 296 | buttons = [] 297 | for groupid in groupids: 298 | try: 299 | ttl = await client.get_chat(int(groupid)) 300 | title = ttl.title 301 | active = await if_active(str(userid), str(groupid)) 302 | act = " - ACTIVE" if active else "" 303 | buttons.append( 304 | [ 305 | InlineKeyboardButton( 306 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}" 307 | ) 308 | ] 309 | ) 310 | except: 311 | pass 312 | if buttons: 313 | await query.message.edit_text( 314 | "Your connected group details ;\n\n", 315 | reply_markup=InlineKeyboardMarkup(buttons) 316 | ) 317 | 318 | elif "alertmessage" in query.data: 319 | grp_id = query.message.chat.id 320 | i = query.data.split(":")[1] 321 | keyword = query.data.split(":")[2] 322 | reply_text, btn, alerts, fileid = await find_filter(grp_id, keyword) 323 | if alerts is not None: 324 | alerts = ast.literal_eval(alerts) 325 | alert = alerts[int(i)] 326 | alert = alert.replace("\\n", "\n").replace("\\t", "\t") 327 | await query.answer(alert,show_alert=True) 328 | 329 | if query.data.startswith("file"): 330 | ident, file_id = query.data.split("#") 331 | files_ = await get_file_details(file_id) 332 | if not files_: 333 | return await query.answer('No such file exist.') 334 | files = files_[0] 335 | title = files.file_name 336 | size=get_size(files.file_size) 337 | f_caption=files.caption 338 | if CUSTOM_FILE_CAPTION: 339 | try: 340 | f_caption=CUSTOM_FILE_CAPTION.format(file_name=title, file_size=size, file_caption=f_caption) 341 | except Exception as e: 342 | logger.exception(e) 343 | f_caption=f_caption 344 | if f_caption is None: 345 | f_caption = f"{files.file_name}" 346 | 347 | try: 348 | if AUTH_CHANNEL and not await is_subscribed(client, query): 349 | await query.answer(url=f"https://t.me/{temp.U_NAME}?start={file_id}") 350 | return 351 | elif P_TTI_SHOW_OFF: 352 | await query.answer(url=f"https://t.me/{temp.U_NAME}?start={file_id}") 353 | return 354 | else: 355 | await client.send_cached_media( 356 | chat_id=query.from_user.id, 357 | file_id=file_id, 358 | caption=f_caption 359 | ) 360 | await query.answer('Check PM, I have sent files in pm',show_alert = True) 361 | except UserIsBlocked: 362 | await query.answer('Unblock the bot mahn !',show_alert = True) 363 | except PeerIdInvalid: 364 | await query.answer(url=f"https://t.me/{temp.U_NAME}?start={file_id}") 365 | except Exception as e: 366 | await query.answer(url=f"https://t.me/{temp.U_NAME}?start={file_id}") 367 | 368 | elif query.data.startswith("checksub"): 369 | if AUTH_CHANNEL and not await is_subscribed(client, query): 370 | await query.answer("🥺𝗙𝗿𝗶𝗲𝗻𝗱.. 𝗧𝗵𝗮𝘁'𝘀 𝗡𝗼𝘁 𝗙𝗮𝗶𝗿 😓𝗣𝗹𝗲𝗮𝘀𝗲 𝗝𝗼𝗶𝗻 𝗧𝗵𝗲 𝗖𝗵𝗮𝗻𝗻𝗲𝗹..🥺",show_alert=True) 371 | return 372 | ident, file_id = query.data.split("#") 373 | files_ = await get_file_details(file_id) 374 | if not files_: 375 | return await query.answer('No such file exist.') 376 | files = files_[0] 377 | title = files.file_name 378 | size=get_size(files.file_size) 379 | f_caption=files.caption 380 | if CUSTOM_FILE_CAPTION: 381 | try: 382 | f_caption=CUSTOM_FILE_CAPTION.format(file_name=title, file_size=size, file_caption=f_caption) 383 | except Exception as e: 384 | logger.exception(e) 385 | f_caption=f_caption 386 | if f_caption is None: 387 | f_caption = f"{title}" 388 | await query.answer() 389 | await client.send_cached_media( 390 | chat_id=query.from_user.id, 391 | file_id=file_id, 392 | caption=f_caption 393 | ) 394 | 395 | elif query.data == "pages": 396 | await query.answer() 397 | elif query.data == "start": 398 | buttons = [[ 399 | InlineKeyboardButton('⚚ ᴀᴅᴅ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ɢʀᴏᴜᴘ ⚚', url=f'http://t.me/{temp.U_NAME}?startgroup=true') 400 | ],[ 401 | InlineKeyboardButton('💠 ʙᴏᴛ ᴜᴘᴅᴀᴛᴇs 💠', url='https://t.me/Cynitebots'), 402 | InlineKeyboardButton('♻️ ʜᴇʟᴘ ♻️', callback_data='help')],[ 403 | InlineKeyboardButton('♻️ ᴀʙᴏᴜᴛ ♻️', callback_data='about'), 404 | InlineKeyboardButton('🔍sᴇᴀʀᴄʜ', switch_inline_query_current_chat=''), ]] 405 | reply_markup = InlineKeyboardMarkup(buttons) 406 | await query.message.edit_text( 407 | text=script.START_TXT.format(query.from_user.mention, temp.U_NAME, temp.B_NAME), 408 | reply_markup=reply_markup, 409 | parse_mode='html' 410 | ) 411 | elif query.data == "help": 412 | buttons = [[ 413 | InlineKeyboardButton('𝗠𝗮𝗻𝘂𝗲𝗹 𝗙𝗶𝗹𝘁𝗲𝗿', callback_data='manuelfilter'), 414 | InlineKeyboardButton('𝗔𝘂𝘁𝗼 𝗙𝗶𝗹𝘁𝗲𝗿', callback_data='autofilter') 415 | ],[ 416 | InlineKeyboardButton('𝗖𝗼𝗻𝗻𝗲𝗰𝘁𝗶𝗼𝗻𝘀', callback_data='coct'), 417 | InlineKeyboardButton('𝗘𝘅𝘁𝗿𝗮 𝗠𝗼𝗱𝗲𝘀', callback_data='extra'), 418 | InlineKeyboardButton('CARBON', callback_data='carbon') 419 | ],[ 420 | InlineKeyboardButton('🏠 𝗛𝗼𝗺𝗲 🏠', callback_data='start'), 421 | InlineKeyboardButton('⚚ 𝗦𝘁𝗮𝘁s ⚚', callback_data='stats') 422 | ]] 423 | reply_markup = InlineKeyboardMarkup(buttons) 424 | await query.message.edit_text( 425 | text=script.HELP_TXT.format(query.from_user.mention), 426 | reply_markup=reply_markup, 427 | parse_mode='html' 428 | ) 429 | elif query.data == "about": 430 | buttons= [[ 431 | InlineKeyboardButton('♥️ SOURCE ♥️', url='https://github.com/CyniteOfficial/Auto-Filter') 432 | ],[ 433 | InlineKeyboardButton('🏠 𝗛𝗼𝗺𝗲 🏠', callback_data='start'), 434 | InlineKeyboardButton('🔐 𝗖𝗹𝗼𝘀𝗲 🔐', callback_data='close_data') 435 | ]] 436 | reply_markup = InlineKeyboardMarkup(buttons) 437 | await query.message.edit_text( 438 | text=script.ABOUT_TXT.format(temp.B_NAME), 439 | reply_markup=reply_markup, 440 | parse_mode='html' 441 | ) 442 | elif query.data == "source": 443 | buttons = [[ 444 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='start') 445 | ]] 446 | reply_markup = InlineKeyboardMarkup(buttons) 447 | await query.message.edit_text( 448 | text=script.SOURCE_TXT, 449 | reply_markup=reply_markup, 450 | parse_mode='html' 451 | ) 452 | elif query.data == "carbon": 453 | buttons = [[ 454 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='start') 455 | ]] 456 | reply_markup = InlineKeyboardMarkup(buttons) 457 | await query.message.edit_text( 458 | text=script.CARBON_TXT, 459 | reply_markup=reply_markup, 460 | parse_mode='html' 461 | ) 462 | elif query.data == "manuelfilter": 463 | buttons = [[ 464 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='help'), 465 | InlineKeyboardButton('⏹️ 𝗕𝘂𝘁𝘁𝗼𝗻𝘀 ⏹', callback_data='button') 466 | ]] 467 | reply_markup = InlineKeyboardMarkup(buttons) 468 | await query.message.edit_text( 469 | text=script.MANUELFILTER_TXT, 470 | reply_markup=reply_markup, 471 | parse_mode='html' 472 | ) 473 | elif query.data == "button": 474 | buttons = [[ 475 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='manuelfilter') 476 | ]] 477 | reply_markup = InlineKeyboardMarkup(buttons) 478 | await query.message.edit_text( 479 | text=script.BUTTON_TXT, 480 | reply_markup=reply_markup, 481 | parse_mode='html' 482 | ) 483 | elif query.data == "autofilter": 484 | buttons = [[ 485 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='help') 486 | ]] 487 | reply_markup = InlineKeyboardMarkup(buttons) 488 | await query.message.edit_text( 489 | text=script.AUTOFILTER_TXT, 490 | reply_markup=reply_markup, 491 | parse_mode='html' 492 | ) 493 | elif query.data == "coct": 494 | buttons = [[ 495 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='help') 496 | ]] 497 | reply_markup = InlineKeyboardMarkup(buttons) 498 | await query.message.edit_text( 499 | text=script.CONNECTION_TXT, 500 | reply_markup=reply_markup, 501 | parse_mode='html' 502 | ) 503 | elif query.data == "extra": 504 | buttons = [[ 505 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='help'), 506 | InlineKeyboardButton('👮‍♂️ 𝗢𝗪𝗡𝗘𝗥 👮', callback_data='admin') 507 | ]] 508 | reply_markup = InlineKeyboardMarkup(buttons) 509 | await query.message.edit_text( 510 | text=script.EXTRAMOD_TXT, 511 | reply_markup=reply_markup, 512 | parse_mode='html' 513 | ) 514 | elif query.data == "admin": 515 | buttons = [[ 516 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='extra') 517 | ]] 518 | reply_markup = InlineKeyboardMarkup(buttons) 519 | await query.message.edit_text( 520 | text=script.ADMIN_TXT, 521 | reply_markup=reply_markup, 522 | parse_mode='html' 523 | ) 524 | elif query.data == "stats": 525 | buttons = [[ 526 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='help'), 527 | InlineKeyboardButton('♻️ 𝗥𝗲𝗳𝗿𝗲𝘀𝗵 ♻️', callback_data='rfrsh') 528 | ]] 529 | reply_markup = InlineKeyboardMarkup(buttons) 530 | total = await Media.count_documents() 531 | users = await db.total_users_count() 532 | chats = await db.total_chat_count() 533 | monsize = await db.get_db_size() 534 | free = 536870912 - monsize 535 | monsize = get_size(monsize) 536 | free = get_size(free) 537 | await query.message.edit_text( 538 | text=script.STATUS_TXT.format(total, users, chats, monsize, free), 539 | reply_markup=reply_markup, 540 | parse_mode='html' 541 | ) 542 | elif query.data == "rfrsh": 543 | await query.answer("Fetching MongoDb DataBase") 544 | buttons = [[ 545 | InlineKeyboardButton('🚶 𝗕𝗮𝗰𝗸 🚶', callback_data='help'), 546 | InlineKeyboardButton('♻️ 𝗥𝗲𝗳𝗿𝗲𝘀𝗵 ♻️', callback_data='rfrsh') 547 | ]] 548 | reply_markup = InlineKeyboardMarkup(buttons) 549 | total = await Media.count_documents() 550 | users = await db.total_users_count() 551 | chats = await db.total_chat_count() 552 | monsize = await db.get_db_size() 553 | free = 536870912 - monsize 554 | monsize = get_size(monsize) 555 | free = get_size(free) 556 | await query.message.edit_text( 557 | text=script.STATUS_TXT.format(total, users, chats, monsize, free), 558 | reply_markup=reply_markup, 559 | parse_mode='html' 560 | ) 561 | 562 | 563 | async def auto_filter(client, msg, spoll=False): 564 | if not spoll: 565 | message = msg 566 | if re.findall("((^\/|^,|^!|^\.|^[\U0001F600-\U000E007F]).*)", message.text): 567 | return 568 | if 2 < len(message.text) < 100: 569 | search = message.text 570 | files, offset, total_results = await get_search_results(search.lower(), offset=0, filter=True) 571 | if not files: 572 | if SPELL_CHECK_REPLY: 573 | return await advantage_spell_chok(msg) 574 | else: 575 | return 576 | else: 577 | return 578 | else: 579 | message = msg.message.reply_to_message # msg will be callback query 580 | search, files, offset, total_results = spoll 581 | if SINGLE_BUTTON: 582 | btn = [ 583 | [ 584 | InlineKeyboardButton( 585 | text=f"[{get_size(file.file_size)}] {file.file_name}", callback_data=f'files#{file.file_id}' 586 | ), 587 | ] 588 | for file in files 589 | ] 590 | else: 591 | btn = [ 592 | [ 593 | InlineKeyboardButton( 594 | text=f"{file.file_name}", 595 | callback_data=f'files#{file.file_id}', 596 | ), 597 | InlineKeyboardButton( 598 | text=f"{get_size(file.file_size)}", 599 | callback_data=f'files_#{file.file_id}', 600 | ), 601 | ] 602 | for file in files 603 | ] 604 | 605 | if offset != "": 606 | key = f"{message.chat.id}-{message.message_id}" 607 | BUTTONS[key] = search 608 | req = message.from_user.id if message.from_user else 0 609 | btn.append( 610 | [InlineKeyboardButton(text=f"🌹 𝗣𝗮𝗴𝗲 1/{round(int(total_results)/10)}",callback_data="pages"), InlineKeyboardButton(text="𝗡𝗲𝘅𝘁 ➡️",callback_data=f"next_{req}_{key}_{offset}")] 611 | ) 612 | else: 613 | btn.append( 614 | [InlineKeyboardButton(text="🌹 𝗣𝗮𝗴𝗲 1/1",callback_data="pages")] 615 | ) 616 | imdb = await get_poster(search, file=(files[0]).file_name) if IMDB else None 617 | if imdb: 618 | cap = IMDB_TEMPLATE.format( 619 | query = search, 620 | title = imdb['title'], 621 | votes = imdb['votes'], 622 | aka = imdb["aka"], 623 | seasons = imdb["seasons"], 624 | box_office = imdb['box_office'], 625 | localized_title = imdb['localized_title'], 626 | kind = imdb['kind'], 627 | imdb_id = imdb["imdb_id"], 628 | cast = imdb["cast"], 629 | runtime = imdb["runtime"], 630 | countries = imdb["countries"], 631 | certificates = imdb["certificates"], 632 | languages = imdb["languages"], 633 | director = imdb["director"], 634 | writer = imdb["writer"], 635 | producer = imdb["producer"], 636 | composer = imdb["composer"], 637 | cinematographer = imdb["cinematographer"], 638 | music_team = imdb["music_team"], 639 | distributors = imdb["distributors"], 640 | release_date = imdb['release_date'], 641 | year = imdb['year'], 642 | genres = imdb['genres'], 643 | poster = imdb['poster'], 644 | plot = imdb['plot'], 645 | rating = imdb['rating'], 646 | url = imdb['url'], 647 | **locals() 648 | ) 649 | else: 650 | cap = f"Movie Name : {search}\nRequested By : {message.from_user.mention}\nGroup : {message.chat.title}" 651 | if imdb and imdb.get('poster'): 652 | try: 653 | hehe = await message.reply_photo(photo=imdb.get('poster'), caption=cap, reply_markup=InlineKeyboardMarkup(btn)) 654 | await asyncio.sleep(1200) 655 | await hehe.delete() 656 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty): 657 | pic = imdb.get('poster') 658 | poster = pic.replace('.jpg', "._V1_UX360.jpg") 659 | hmm = await message.reply_photo(photo=poster, caption=cap, reply_markup=InlineKeyboardMarkup(btn)) 660 | await asyncio.sleep(1200) 661 | except Exception as e: 662 | logger.exception(e) 663 | fek = await message.reply_text(text=cap, disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup(btn)) 664 | await asyncio.sleep(1200) 665 | else: 666 | fuk = await message.reply_text(text=cap, disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup(btn)) 667 | await asyncio.sleep(1200) 668 | await fuk.delete() 669 | 670 | 671 | async def advantage_spell_chok(msg): 672 | query = re.sub(r"\b(pl(i|e)*?(s|z+|ease|se|ese|(e+)s(e)?)|((send|snd|giv(e)?|gib)(\sme)?)|movie(s)?|new|latest|br((o|u)h?)*|^h(e|a)?(l)*(o)*|mal(ayalam)?|t(h)?amil|file|that|find|und(o)*|kit(t(i|y)?)?o(w)?|thar(u)?(o)*w?|kittum(o)*|aya(k)*(um(o)*)?|full\smovie|any(one)|with\ssubtitle(s)?)", "", msg.text, flags=re.IGNORECASE) # plis contribute some common words 673 | query = query.strip() + " movie" 674 | g_s = await search_gagala(query) 675 | g_s += await search_gagala(msg.text) 676 | gs_parsed = [] 677 | if not g_s: 678 | k = await msg.reply("I couldn't find any movie in that name.") 679 | await asyncio.sleep(8) 680 | await k.delete() 681 | return 682 | regex = re.compile(r".*(imdb|wikipedia).*", re.IGNORECASE) # look for imdb / wiki results 683 | gs = list(filter(regex.match, g_s)) 684 | gs_parsed = [re.sub(r'\b(\-([a-zA-Z-\s])\-\simdb|(\-\s)?imdb|(\-\s)?wikipedia|\(|\)|\-|reviews|full|all|episode(s)?|film|movie|series)', '', i, flags=re.IGNORECASE) for i in gs] 685 | if not gs_parsed: 686 | reg = re.compile(r"watch(\s[a-zA-Z0-9_\s\-\(\)]*)*\|.*", re.IGNORECASE) # match something like Watch Niram | Amazon Prime 687 | for mv in g_s: 688 | match = reg.match(mv) 689 | if match: 690 | gs_parsed.append(match.group(1)) 691 | user = msg.from_user.id if msg.from_user else 0 692 | movielist = [] 693 | gs_parsed = list(dict.fromkeys(gs_parsed)) # removing duplicates https://stackoverflow.com/a/7961425 694 | if len(gs_parsed) > 3: 695 | gs_parsed = gs_parsed[:3] 696 | if gs_parsed: 697 | for mov in gs_parsed: 698 | imdb_s = await get_poster(mov.strip(), bulk=True) # searching each keyword in imdb 699 | if imdb_s: 700 | movielist += [movie.get('title') for movie in imdb_s] 701 | movielist += [(re.sub(r'(\-|\(|\)|_)', '', i, flags=re.IGNORECASE)).strip() for i in gs_parsed] 702 | movielist = list(dict.fromkeys(movielist)) # removing duplicates 703 | if not movielist: 704 | k = await msg.reply("I couldn't find anything related to that. Check your spelling") 705 | await asyncio.sleep(8) 706 | await k.delete() 707 | return 708 | SPELL_CHECK[msg.message_id] = movielist 709 | btn = [[ 710 | InlineKeyboardButton( 711 | text=movie.strip(), 712 | callback_data=f"spolling#{user}#{k}", 713 | ) 714 | ] for k, movie in enumerate(movielist)] 715 | btn.append([InlineKeyboardButton(text="Close", callback_data=f'spolling#{user}#close_spellcheck')]) 716 | await msg.reply("𝙲𝙷𝙴𝙲𝙺 𝚈𝙾𝚄𝚁 𝙼𝙾𝚅𝙸𝙴 𝙾𝙽 𝚃𝙷𝙴 𝙶𝙸𝚅𝙴𝙽 𝙻𝙸𝚂𝚃 𝙰𝙽𝙳 𝚂𝙴𝙻𝙴𝙲𝚃 𝚈𝙾𝚄𝚁 𝙼𝙾𝚅𝙸𝙴𝚂.📌", reply_markup=InlineKeyboardMarkup(btn)) 717 | 718 | 719 | async def manual_filters(client, message, text=False): 720 | group_id = message.chat.id 721 | name = text or message.text 722 | reply_id = message.reply_to_message.message_id if message.reply_to_message else message.message_id 723 | keywords = await get_filters(group_id) 724 | for keyword in reversed(sorted(keywords, key=len)): 725 | pattern = r"( |^|[^\w])" + re.escape(keyword) + r"( |$|[^\w])" 726 | if re.search(pattern, name, flags=re.IGNORECASE): 727 | reply_text, btn, alert, fileid = await find_filter(group_id, keyword) 728 | 729 | if reply_text: 730 | reply_text = reply_text.replace("\\n", "\n").replace("\\t", "\t") 731 | 732 | if btn is not None: 733 | try: 734 | if fileid == "None": 735 | if btn == "[]": 736 | await client.send_message(group_id, reply_text, disable_web_page_preview=True) 737 | else: 738 | button = eval(btn) 739 | await client.send_message( 740 | group_id, 741 | reply_text, 742 | disable_web_page_preview=True, 743 | reply_markup=InlineKeyboardMarkup(button), 744 | reply_to_message_id = reply_id 745 | ) 746 | elif btn == "[]": 747 | await client.send_cached_media( 748 | group_id, 749 | fileid, 750 | caption=reply_text or "", 751 | reply_to_message_id = reply_id 752 | ) 753 | else: 754 | button = eval(btn) 755 | await message.reply_cached_media( 756 | fileid, 757 | caption=reply_text or "", 758 | reply_markup=InlineKeyboardMarkup(button), 759 | reply_to_message_id = reply_id 760 | ) 761 | except Exception as e: 762 | logger.exception(e) 763 | break 764 | else: 765 | return False 766 | --------------------------------------------------------------------------------