├── Procfile ├── runtime.txt ├── SAFARI ├── __init__.py ├── utils │ ├── exceptions.py │ ├── file_size.py │ ├── human_readable.py │ ├── config_parser.py │ ├── keepalive.py │ ├── time_format.py │ ├── clients.py │ ├── render_template.py │ ├── __init__.py │ ├── file_properties.py │ └── custom_dl.py ├── template │ ├── __init__.py │ ├── dl.html │ └── req.html └── route.py ├── Dockerfile ├── docker-compose.yml ├── start.sh ├── requirements.txt ├── plugins ├── Dev_Feature │ ├── features │ │ ├── stickerid.py │ │ ├── telegraph.py │ │ └── font.py │ ├── autojoin.py │ ├── Request.py │ ├── getfile.py │ ├── Redeem.py │ ├── Group_Verify.py │ └── Premium.py ├── banned.py ├── files_delete.py ├── broadcast.py ├── channel.py ├── connection.py ├── misc.py ├── p_ttishow.py └── index.py ├── logging.conf ├── database ├── safari_reffer.py ├── connections_mdb.py ├── ia_filterdb.py └── users_chats_db.py ├── app.json ├── bot.py ├── README.md ├── info.py ├── Script.py └── utils.py /Procfile: -------------------------------------------------------------------------------- 1 | web: python3 bot.py 2 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.13 2 | -------------------------------------------------------------------------------- /SAFARI/__init__.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | StartTime = time.time() 4 | __version__ = 1.1 5 | -------------------------------------------------------------------------------- /SAFARI/utils/exceptions.py: -------------------------------------------------------------------------------- 1 | class InvalidHash(Exception): 2 | message = "Invalid hash" 3 | 4 | class FIleNotFound(Exception): 5 | message = "File not found" 6 | -------------------------------------------------------------------------------- /SAFARI/template/__init__.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from SAFARI.route import routes 3 | 4 | 5 | async def web_server(): 6 | web_app = web.Application(client_max_size=30000000) 7 | web_app.add_routes(routes) 8 | return web_app 9 | -------------------------------------------------------------------------------- /SAFARI/utils/file_size.py: -------------------------------------------------------------------------------- 1 | def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']): 2 | """ Returns a human readable string representation of bytes """ 3 | return str(bytes) + units[0] if int(bytes) < 1024 else human_size(int(bytes)>>10, units[1:]) 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.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 /Safari-Filter-Bot 10 | WORKDIR /Safari-Filter-Bot 11 | COPY start.sh /start.sh 12 | CMD ["/bin/bash", "/start.sh"] -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.10" 2 | services: 3 | worker: 4 | build: . 5 | environment: 6 | BOT_TOKEN: $BOT_TOKEN 7 | API_ID: $API_ID 8 | API_HASH: $API_HASH 9 | CHANNELS: $CHANNELS 10 | ADMINS: $ADMINS 11 | LOG_CHANNEL: $LOG_CHANNEL 12 | DATABASE_NAME: $DATABASE_NAME 13 | DATABASE_URI: $DATABASE_URI 14 | HEROKU_API_KEY: $HEROKU_API_KEY 15 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | if [ -z $UPSTREAM_REPO ] 2 | then 3 | echo "Cloning main Repository" 4 | git clone https://github.com/Safaridevv/Safari-Filter-Bot.git /Safari-Filter-Bot 5 | else 6 | echo "Cloning Custom Repo from $UPSTREAM_REPO " 7 | git clone $UPSTREAM_REPO /SuperBot 8 | fi 9 | cd /Safari-Filter-Bot 10 | pip3 install -U -r requirements.txt 11 | echo "Starting DQ-The-File-Donor...." 12 | python3 bot.py 13 | -------------------------------------------------------------------------------- /SAFARI/utils/human_readable.py: -------------------------------------------------------------------------------- 1 | def humanbytes(size): 2 | # https://stackoverflow.com/a/49361727/4723940 3 | # 2**10 = 1024 4 | if not size: 5 | return "" 6 | power = 2**10 7 | n = 0 8 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'} 9 | while size > power: 10 | size /= power 11 | n += 1 12 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B' 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrofork==2.3.43 2 | python-telegram-bot 3 | umongo 4 | tgcrypto 5 | pymongo[srv]==3.12.3 6 | motor==2.5.1 7 | marshmallow==3.14.1 8 | requests 9 | bs4 10 | git+https://github.com/Joelkb/cinemagoer 11 | datetime 12 | pytz 13 | aiohttp 14 | cinemagoer 15 | shortzy 16 | 17 | PyLeaves==1.0.2 18 | cinemagoer 19 | shortzy==0.0.8 20 | aiofiles 21 | pyromod==1.5 22 | 23 | telegraph 24 | openai 25 | 26 | jinja2 27 | apscheduler 28 | pyshorteners 29 | colorama 30 | fuzzywuzzy 31 | python-Levenshtein 32 | googletrans==4.0.0-rc1 33 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/features/stickerid.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from pyrogram import Client, filters 4 | 5 | @Client.on_message(filters.command(["sticker_id"])) 6 | async def stickerid(bot, message): 7 | if message.reply_to_message.sticker: 8 | await message.reply(f"**Sticker ID is** \n `{message.reply_to_message.sticker.file_id}` \n \n ** Unique ID is ** \n\n`{message.reply_to_message.sticker.file_unique_id}`", quote=True) 9 | else: 10 | await message.reply("Oops !! Not a sticker file") 11 | -------------------------------------------------------------------------------- /SAFARI/utils/config_parser.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | from typing import Dict, Optional 3 | 4 | 5 | class TokenParser: 6 | def __init__(self, config_file: Optional[str] = None): 7 | self.tokens = {} 8 | self.config_file = config_file 9 | 10 | def parse_from_env(self) -> Dict[int, str]: 11 | self.tokens = dict( 12 | (c + 1, t) 13 | for c, (_, t) in enumerate( 14 | filter( 15 | lambda n: n[0].startswith("MULTI_TOKEN"), sorted(environ.items()) 16 | ) 17 | ) 18 | ) 19 | return self.tokens 20 | -------------------------------------------------------------------------------- /SAFARI/utils/keepalive.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import aiohttp 4 | import traceback 5 | from info import * 6 | 7 | 8 | async def ping_server(): 9 | sleep_time = PING_INTERVAL 10 | while True: 11 | await asyncio.sleep(sleep_time) 12 | try: 13 | async with aiohttp.ClientSession( 14 | timeout=aiohttp.ClientTimeout(total=10) 15 | ) as session: 16 | async with session.get(URL) as resp: 17 | logging.info("Pinged server with response: {}".format(resp.status)) 18 | except TimeoutError: 19 | logging.warning("Couldn't connect to the site URL..!") 20 | except Exception: 21 | traceback.print_exc() 22 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/autojoin.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import pyrogram 4 | from pyrogram import Client, filters 5 | 6 | @Client.on_chat_join_request() 7 | async def auto_accept_request(client, chat_member_update): 8 | chat_id = chat_member_update.chat.id 9 | user_id = chat_member_update.from_user.id 10 | 11 | try: 12 | await client.get_chat_member(chat_id, client.me.id) 13 | await client.approve_chat_join_request(chat_id, user_id) 14 | #await client.send_message(user_id, f"ʜᴇʏ {chat_member_update.from_user.mention}!\nʀᴇǫᴜᴇsᴛ ʜᴀs ʙᴇᴇɴ ᴀᴄᴄᴇᴘᴛᴇᴅ ᴡᴇʟᴄᴏᴍᴇ ᴛᴏ {chat_member_update.chat.title}") 15 | 16 | except Exception as e: 17 | print(f"Error approving request: {e}") 18 | -------------------------------------------------------------------------------- /logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=consoleHandler,fileHandler 6 | 7 | [formatters] 8 | keys=consoleFormatter,fileFormatter 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=consoleHandler,fileHandler 13 | 14 | [handler_consoleHandler] 15 | class=StreamHandler 16 | level=INFO 17 | formatter=consoleFormatter 18 | args=(sys.stdout,) 19 | 20 | [handler_fileHandler] 21 | class=FileHandler 22 | level=ERROR 23 | formatter=fileFormatter 24 | args=('Logs.txt','w',) 25 | 26 | [formatter_consoleFormatter] 27 | format=%(asctime)s - %(lineno)d - %(name)s - %(module)s - %(levelname)s - %(message)s 28 | datefmt=%I:%M:%S %p 29 | 30 | [formatter_fileFormatter] 31 | format=[%(asctime)s:%(name)s:%(lineno)d:%(levelname)s] %(message)s 32 | datefmt=%m/%d/%Y %I:%M:%S %p -------------------------------------------------------------------------------- /SAFARI/utils/time_format.py: -------------------------------------------------------------------------------- 1 | def get_readable_time(seconds: int) -> str: 2 | count = 0 3 | readable_time = "" 4 | time_list = [] 5 | time_suffix_list = ["s", "m", "h", " days"] 6 | while count < 4: 7 | count += 1 8 | if count < 3: 9 | remainder, result = divmod(seconds, 60) 10 | else: 11 | remainder, result = divmod(seconds, 24) 12 | if seconds == 0 and remainder == 0: 13 | break 14 | time_list.append(int(result)) 15 | seconds = int(remainder) 16 | for x in range(len(time_list)): 17 | time_list[x] = str(time_list[x]) + time_suffix_list[x] 18 | if len(time_list) == 4: 19 | readable_time += time_list.pop() + ", " 20 | time_list.reverse() 21 | readable_time += ": ".join(time_list) 22 | return readable_time 23 | -------------------------------------------------------------------------------- /database/safari_reffer.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import pymongo 4 | from info import DATABASE_URI, DATABASE_NAME 5 | import logging 6 | 7 | logger = logging.getLogger(__name__) 8 | logger.setLevel(logging.ERROR) 9 | 10 | myclient = pymongo.MongoClient(DATABASE_URI) 11 | mydb = myclient[DATABASE_NAME] 12 | 13 | 14 | class UserPoint: 15 | def __init__(self): 16 | self.user_collection = mydb["referusers"] 17 | self.refer_collection = mydb["refers"] 18 | 19 | def add_user(self, user_id): 20 | if not self.is_user_in_list(user_id): 21 | self.user_collection.insert_one({'user_id': user_id}) 22 | 23 | def remove_user(self, user_id): 24 | self.user_collection.delete_one({'user_id': user_id}) 25 | 26 | def is_user_in_list(self, user_id): 27 | return bool(self.user_collection.find_one({'user_id': user_id})) 28 | 29 | def add_refer_points(self, user_id: int, points: int): 30 | self.refer_collection.update_one( 31 | {'user_id': user_id}, 32 | {'$set': {'points': points}}, 33 | upsert=True 34 | ) 35 | 36 | def get_refer_points(self, user_id: int): 37 | user = self.refer_collection.find_one({'user_id': user_id}) 38 | return user.get('points') if user else 0 39 | 40 | 41 | sdb = UserPoint() 42 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/features/telegraph.py: -------------------------------------------------------------------------------- 1 | import os, asyncio 2 | from pyrogram import Client, filters 3 | from pyrogram.types import * 4 | from telegraph import upload_file 5 | 6 | 7 | @Client.on_message(filters.command("telegraph") & filters.private) 8 | async def telegraph_upload(bot, update): 9 | replied = update.reply_to_message 10 | if not replied: 11 | return await update.reply_text("Reply to a photo or video.") 12 | 13 | if not (replied.photo or replied.video): 14 | return await update.reply_text("Please reply with a valid media.") 15 | 16 | text = await update.reply_text("Downloading...", disable_web_page_preview=True) 17 | media = await replied.download() 18 | await text.edit_text("Uploading...", disable_web_page_preview=True) 19 | 20 | try: 21 | response = upload_file(media) 22 | except Exception as error: 23 | print(error) 24 | return await text.edit_text(text=f"Error: {error}", disable_web_page_preview=True) 25 | 26 | try: 27 | os.remove(media) 28 | except Exception as error: 29 | print(error) 30 | return 31 | 32 | # Access the first item of the response list 33 | await text.edit_text( 34 | text=f"https://telegra.ph{response[0]}", 35 | disable_web_page_preview=True 36 | ) 37 | -------------------------------------------------------------------------------- /plugins/banned.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from pyrogram import Client, filters 4 | from utils import temp 5 | from pyrogram.types import Message 6 | from database.users_chats_db import db 7 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 8 | from info import SUPPORT_CHAT 9 | 10 | async def banned_users(_, client, message: Message): 11 | return ( 12 | message.from_user is not None or not message.sender_chat 13 | ) and message.from_user.id in temp.BANNED_USERS 14 | banned_user = filters.create(banned_users) 15 | async def disabled_chat(_, client, message: Message): 16 | return message.chat.id in temp.BANNED_CHATS 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 Me. \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('Support', 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\nMy admins has restricted me from working here ! If you want to know more about it contact support..\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 | -------------------------------------------------------------------------------- /SAFARI/utils/clients.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from info import * 4 | from pyrogram import Client 5 | from SAFARI.utils.config_parser import TokenParser 6 | from SAFARI.utils import multi_clients, work_loads, SafariBot 7 | 8 | 9 | async def initialize_clients(): 10 | multi_clients[0] = SafariBot 11 | work_loads[0] = 0 12 | all_tokens = TokenParser().parse_from_env() 13 | if not all_tokens: 14 | print("No additional clients found, using default client") 15 | return 16 | 17 | async def start_client(client_id, token): 18 | try: 19 | print(f"Starting - Client {client_id}") 20 | if client_id == len(all_tokens): 21 | await asyncio.sleep(2) 22 | print("This will take some time, please wait...") 23 | client = await Client( 24 | name=str(client_id), 25 | api_id=API_ID, 26 | api_hash=API_HASH, 27 | bot_token=token, 28 | sleep_threshold=SLEEP_THRESHOLD, 29 | no_updates=True, 30 | in_memory=True 31 | ).start() 32 | work_loads[client_id] = 0 33 | return client_id, client 34 | except Exception: 35 | logging.error(f"Failed starting Client - {client_id} Error:", exc_info=True) 36 | 37 | clients = await asyncio.gather(*[start_client(i, token) for i, token in all_tokens.items()]) 38 | multi_clients.update(dict(clients)) 39 | if len(multi_clients) != 1: 40 | MULTI_CLIENT = True 41 | print("Multi-Client Mode Enabled") 42 | else: 43 | print("No additional clients were initialized, using default client") 44 | -------------------------------------------------------------------------------- /SAFARI/utils/render_template.py: -------------------------------------------------------------------------------- 1 | import jinja2 2 | from info import * 3 | from SAFARI.utils import SafariBot 4 | from SAFARI.utils.human_readable import humanbytes 5 | from SAFARI.utils.file_properties import get_file_ids 6 | from SAFARI.utils.exceptions import InvalidHash 7 | import urllib.parse 8 | import logging 9 | import aiohttp 10 | 11 | 12 | async def render_page(id, secure_hash, src=None): 13 | file = await SafariBot.get_messages(int(BIN_CHANNEL), int(id)) 14 | file_data = await get_file_ids(SafariBot, int(BIN_CHANNEL), int(id)) 15 | if file_data.unique_id[:6] != secure_hash: 16 | logging.debug(f"link hash: {secure_hash} - {file_data.unique_id[:6]}") 17 | logging.debug(f"Invalid hash for message with - ID {id}") 18 | raise InvalidHash 19 | 20 | src = urllib.parse.urljoin( 21 | URL, 22 | f"{id}/{urllib.parse.quote_plus(file_data.file_name)}?hash={secure_hash}", 23 | ) 24 | 25 | tag = file_data.mime_type.split("/")[0].strip() 26 | file_size = humanbytes(file_data.file_size) 27 | if tag in ["video", "audio"]: 28 | template_file = "SAFARI/template/req.html" 29 | else: 30 | template_file = "SAFARI/template/dl.html" 31 | async with aiohttp.ClientSession() as s: 32 | async with s.get(src) as u: 33 | file_size = humanbytes(int(u.headers.get("Content-Length"))) 34 | 35 | with open(template_file) as f: 36 | template = jinja2.Template(f.read()) 37 | 38 | file_name = file_data.file_name.replace("_", " ") 39 | 40 | return template.render( 41 | file_name=file_name, 42 | file_url=src, 43 | file_size=file_size, 44 | file_unique_id=file_data.unique_id, 45 | ) 46 | -------------------------------------------------------------------------------- /SAFARI/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | logging.config.fileConfig('logging.conf') 4 | logging.getLogger().setLevel(logging.INFO) 5 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 6 | logging.getLogger("imdbpy").setLevel(logging.ERROR) 7 | logging.basicConfig( 8 | level=logging.INFO, 9 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" 10 | ) 11 | logging.getLogger("aiohttp").setLevel(logging.ERROR) 12 | logging.getLogger("aiohttp.web").setLevel(logging.ERROR) 13 | 14 | from pyrogram import Client 15 | from database.ia_filterdb import Media 16 | from info import * 17 | from utils import temp 18 | from typing import Union, Optional, AsyncGenerator 19 | from pyrogram import types 20 | from aiohttp import web 21 | 22 | from pyrogram import Client 23 | from info import * 24 | 25 | class SafariXBot(Client): 26 | 27 | def __init__(self): 28 | super().__init__( 29 | name=SESSION, 30 | api_id=API_ID, 31 | api_hash=API_HASH, 32 | bot_token=BOT_TOKEN, 33 | workers=50, 34 | plugins={"root": "plugins"}, 35 | sleep_threshold=5, 36 | ) 37 | async def iter_messages( 38 | self, 39 | chat_id: Union[int, str], 40 | limit: int, 41 | offset: int = 0, 42 | ) -> Optional[AsyncGenerator["types.Message", None]]: 43 | current = offset 44 | while True: 45 | new_diff = min(200, limit - current) 46 | if new_diff <= 0: 47 | return 48 | messages = await self.get_messages(chat_id, list(range(current, current+new_diff+1))) 49 | for message in messages: 50 | yield message 51 | current += 1 52 | 53 | SafariBot = SafariXBot() 54 | 55 | multi_clients = {} 56 | work_loads = {} 57 | -------------------------------------------------------------------------------- /plugins/files_delete.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import re 4 | import logging 5 | from pyrogram import Client, filters 6 | from info import DELETE_CHANNELS 7 | from database.ia_filterdb import Media, unpack_new_file_id 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | media_filter = filters.document | filters.video | filters.audio 12 | 13 | 14 | @Client.on_message(filters.chat(DELETE_CHANNELS) & media_filter) 15 | async def deletemultiplemedia(bot, message): 16 | """Delete Multiple files from database""" 17 | 18 | for file_type in ("document", "video", "audio"): 19 | media = getattr(message, file_type, None) 20 | if media is not None: 21 | break 22 | else: 23 | return 24 | 25 | file_id, file_ref = unpack_new_file_id(media.file_id) 26 | 27 | result = await Media.collection.delete_one({ 28 | '_id': file_id, 29 | }) 30 | if result.deleted_count: 31 | logger.info('File is successfully deleted from database.') 32 | else: 33 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 34 | result = await Media.collection.delete_many({ 35 | 'file_name': file_name, 36 | 'file_size': media.file_size, 37 | 'mime_type': media.mime_type 38 | }) 39 | if result.deleted_count: 40 | logger.info('File is successfully deleted from database.') 41 | else: 42 | result = await Media.collection.delete_many({ 43 | 'file_name': media.file_name, 44 | 'file_size': media.file_size, 45 | 'mime_type': media.mime_type 46 | }) 47 | if result.deleted_count: 48 | logger.info('File is successfully deleted from database.') 49 | else: 50 | logger.info('File not found in database.') 51 | -------------------------------------------------------------------------------- /SAFARI/utils/file_properties.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client 2 | from typing import Any, Optional 3 | from pyrogram.types import Message 4 | from pyrogram.file_id import FileId 5 | from pyrogram.raw.types.messages import Messages 6 | from SAFARI.utils.exceptions import FIleNotFound 7 | 8 | 9 | async def parse_file_id(message: "Message") -> Optional[FileId]: 10 | media = get_media_from_message(message) 11 | if media: 12 | return FileId.decode(media.file_id) 13 | 14 | async def parse_file_unique_id(message: "Messages") -> Optional[str]: 15 | media = get_media_from_message(message) 16 | if media: 17 | return media.file_unique_id 18 | 19 | async def get_file_ids(client: Client, chat_id: int, id: int) -> Optional[FileId]: 20 | message = await client.get_messages(chat_id, id) 21 | if message.empty: 22 | raise FIleNotFound 23 | media = get_media_from_message(message) 24 | file_unique_id = await parse_file_unique_id(message) 25 | file_id = await parse_file_id(message) 26 | setattr(file_id, "file_size", getattr(media, "file_size", 0)) 27 | setattr(file_id, "mime_type", getattr(media, "mime_type", "")) 28 | setattr(file_id, "file_name", getattr(media, "file_name", "")) 29 | setattr(file_id, "unique_id", file_unique_id) 30 | return file_id 31 | 32 | def get_media_from_message(message: "Message") -> Any: 33 | media_types = ( 34 | "audio", 35 | "document", 36 | "photo", 37 | "sticker", 38 | "animation", 39 | "video", 40 | "voice", 41 | "video_note", 42 | ) 43 | for attr in media_types: 44 | media = getattr(message, attr, None) 45 | if media: 46 | return media 47 | 48 | 49 | def get_hash(media_msg: Message) -> str: 50 | media = get_media_from_message(media_msg) 51 | return getattr(media, "file_unique_id", "")[:6] 52 | 53 | def get_name(media_msg: Message) -> str: 54 | media = get_media_from_message(media_msg) 55 | return getattr(media, 'file_name', "") 56 | 57 | def get_media_file_size(m): 58 | media = get_media_from_message(m) 59 | return getattr(media, "file_size", 0) 60 | -------------------------------------------------------------------------------- /SAFARI/template/dl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %s 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | %s 22 |
23 |
24 | 25 |
26 | 27 | 33 | 34 |
35 | 36 | 37 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Safari-Filter-Bot", 3 | "description": "When you going to send file on telegram channel this bot will save that in database, So you can search that easily in inline mode", 4 | "stack": "container", 5 | "keywords": [ 6 | "telegram", 7 | "auto-filter", 8 | "filter", 9 | "best", 10 | "indian", 11 | "pyrogram", 12 | "media", 13 | "search", 14 | "channel", 15 | "index", 16 | "inline" 17 | ], 18 | "website": "https://github.com/Safaridevv/Safari-Filter-Bot", 19 | "repository": "https://github.com/Safaridevv/Safari-Filter-Bot", 20 | "env": { 21 | "BOT_TOKEN": { 22 | "description": "Your bot token.", 23 | "required": true 24 | }, 25 | "API_ID": { 26 | "description": "Get this value from https://my.telegram.org", 27 | "required": true 28 | }, 29 | "API_HASH": { 30 | "description": "Get this value from https://my.telegram.org", 31 | "required": true 32 | }, 33 | "CHANNELS": { 34 | "description": "Username or ID of channel or group. Separate multiple IDs by space.", 35 | "required": false 36 | }, 37 | "ADMINS": { 38 | "description": "Username or ID of Admin. Separate multiple Admins by space.", 39 | "required": true 40 | }, 41 | "PICS": { 42 | "description": "Add some telegraph link of pictures .", 43 | "required": false 44 | }, 45 | "LOG_CHANNEL": { 46 | "description": "Bot Logs,Give a channel id with -100xxxxxxx", 47 | "required": true 48 | }, 49 | "AUTH_CHANNEL": { 50 | "description": "ID of channel.Make sure bot is admin in this channel. Without subscribing this channel users cannot use bot.", 51 | "required": false 52 | }, 53 | "DATABASE_URI": { 54 | "description": "mongoDB URI. Get this value from https://www.mongodb.com. For more help watch this video - https://youtu.be/dsuTn4qV2GA", 55 | "required": true 56 | }, 57 | "DATABASE_NAME": { 58 | "description": "Name of the database in mongoDB. For more help watch this video - https://youtu.be/dsuTn4qV2GA", 59 | "required": false 60 | }, 61 | "FQDN": { 62 | "description": "change this url by command /setlink FQDN {your app link}", 63 | "value": "https://safaribots-4265615e2c5e.herokuapp.com/", 64 | "required": true 65 | }, 66 | "COLLECTION_NAME": { 67 | "description": "Name of the collections. Defaults to Telegram_files. If you are using the same database, then use different collection name for each bot", 68 | "value": "Telegram_files", 69 | "required": false 70 | } 71 | }, 72 | "addons": [], 73 | "buildpacks": [{ 74 | "url": "heroku/python" 75 | }], 76 | "formation": { 77 | "worker": { 78 | "quantity": 1, 79 | "size": "eco" 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by Safaridev 2 | # Please do not remove this credit 3 | import logging 4 | import logging.config 5 | 6 | # Get logging configurations 7 | logging.config.fileConfig('logging.conf') 8 | logging.getLogger().setLevel(logging.INFO) 9 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 10 | logging.getLogger("imdbpy").setLevel(logging.ERROR) 11 | logging.getLogger("cinemagoer").setLevel(logging.ERROR) 12 | 13 | from pyrogram import Client, __version__ 14 | from pyrogram.raw.all import layer 15 | from database.ia_filterdb import Media 16 | from database.users_chats_db import db 17 | from info import SESSION, API_ID, API_HASH, BOT_TOKEN, LOG_STR, LOG_CHANNEL, PORT, BIN_CHANNEL, ON_HEROKU 18 | from typing import Union, Optional, AsyncGenerator 19 | from pyrogram import types 20 | from Script import script 21 | from datetime import date, datetime 22 | import pytz 23 | from utils import temp, check_reset_time 24 | logging.basicConfig( 25 | level=logging.INFO, 26 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" 27 | ) 28 | logging.getLogger("aiohttp").setLevel(logging.ERROR) 29 | logging.getLogger("aiohttp.web").setLevel(logging.ERROR) 30 | import asyncio 31 | import sys 32 | import importlib 33 | import glob 34 | from pathlib import Path 35 | from aiohttp import web 36 | from pyrogram import idle 37 | from SAFARI.template import web_server 38 | from SAFARI.utils import SafariBot 39 | from SAFARI.utils.keepalive import ping_server 40 | from SAFARI.utils.clients import initialize_clients 41 | from plugins.Dev_Feature.Premium import check_expired_premium 42 | 43 | ppath = "plugins/*.py" 44 | files = glob.glob(ppath) 45 | SafariBot.start() 46 | loop = asyncio.get_event_loop() 47 | 48 | 49 | async def start(): 50 | print('\n') 51 | print('Initalizing Your Bot') 52 | bot_info = await SafariBot.get_me() 53 | SafariBot.username = bot_info.username 54 | await initialize_clients() 55 | for name in files: 56 | with open(name) as a: 57 | patt = Path(a.name) 58 | plugin_name = patt.stem.replace(".py", "") 59 | plugins_dir = Path(f"plugins/{plugin_name}.py") 60 | import_path = "plugins.{}".format(plugin_name) 61 | spec = importlib.util.spec_from_file_location(import_path, plugins_dir) 62 | load = importlib.util.module_from_spec(spec) 63 | spec.loader.exec_module(load) 64 | sys.modules["plugins." + plugin_name] = load 65 | print("All Files Imported => " + plugin_name) 66 | if ON_HEROKU: 67 | asyncio.create_task(ping_server()) 68 | b_users, b_chats = await db.get_banned() 69 | temp.BANNED_USERS = b_users 70 | temp.BANNED_CHATS = b_chats 71 | await Media.ensure_indexes() 72 | me = await SafariBot.get_me() 73 | temp.ME = me.id 74 | temp.U_NAME = me.username 75 | temp.B_NAME = me.first_name 76 | SafariBot.username = '@' + me.username 77 | SafariBot.loop.create_task(check_expired_premium(SafariBot)) 78 | SafariBot.loop.create_task(check_reset_time()) 79 | logging.info(f"{me.first_name} with for Pyrogram v{__version__} (Layer {layer}) started on {me.username}.") 80 | logging.info(LOG_STR) 81 | logging.info(script.LOGO) 82 | tz = pytz.timezone('Asia/Kolkata') 83 | today = date.today() 84 | now = datetime.now(tz) 85 | time = now.strftime("%H:%M:%S %p") 86 | app = web.AppRunner(await web_server()) 87 | await app.setup() 88 | bind_address = "0.0.0.0" 89 | await web.TCPSite(app, bind_address, PORT).start() 90 | await idle() 91 | await SafariBot.send_message(chat_id=LOG_CHANNEL, text=script.RESTART_TXT.format(temp.U_NAME, temp.B_NAME, today, time)) 92 | 93 | 94 | if __name__ == '__main__': 95 | try: 96 | loop.run_until_complete(start()) 97 | except KeyboardInterrupt: 98 | logging.info('Service Stopped Bye 👋') -------------------------------------------------------------------------------- /plugins/broadcast.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from pyrogram import Client, filters 4 | import datetime 5 | import time 6 | from database.users_chats_db import db 7 | from info import ADMINS 8 | from utils import broadcast_messages 9 | import asyncio 10 | 11 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply) 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 | 19 | start_time = time.time() 20 | total_users = await db.total_users_count() 21 | done = 0 22 | blocked = 0 23 | deleted = 0 24 | failed =0 25 | 26 | success = 0 27 | 28 | sem = asyncio.Semaphore(10) # limit the number of concurrent tasks to 100 29 | 30 | async def run_task(user): 31 | async with sem: 32 | res = await broadcast_func(user, b_msg) 33 | return res 34 | 35 | tasks = [] 36 | 37 | async for user in users: 38 | task = asyncio.ensure_future(run_task(user)) 39 | tasks.append(task) 40 | 41 | for res in await asyncio.gather(*tasks): 42 | success1, blocked1, deleted1, failed1, done1 = res 43 | done += done1 44 | blocked += blocked1 45 | deleted += deleted1 46 | failed += failed1 47 | success += success1 48 | 49 | if not done % 50: 50 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 51 | 52 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 53 | 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}") 54 | 55 | @Client.on_message(filters.command("grp_broadcast") & filters.user(ADMINS) & filters.reply) 56 | async def grp_brodcst(bot, message): 57 | chats = await db.get_all_chats() 58 | b_msg = message.reply_to_message 59 | sts = await message.reply_text( 60 | text='Broadcasting your messages...' 61 | ) 62 | start_time = time.time() 63 | total_chats = await db.total_chat_count() 64 | done = 0 65 | failed =0 66 | 67 | success = 0 68 | async for chat in chats: 69 | pti, sh = await broadcast_messages(int(chat['id']), b_msg) 70 | if pti: 71 | success += 1 72 | elif pti == False: 73 | if sh == "Blocked": 74 | blocked+=1 75 | elif sh == "Deleted": 76 | deleted += 1 77 | elif sh == "Error": 78 | failed += 1 79 | done += 1 80 | await asyncio.sleep(2) 81 | if not done % 20: 82 | await sts.edit(f"Broadcast in progress:\n\nTotal Chats {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}") 83 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 84 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Chats {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}") 85 | 86 | async def broadcast_func(user, b_msg): 87 | success, blocked, deleted, failed, done = 0, 0, 0, 0, 0 88 | pti, sh = await broadcast_messages(int(user['id']), b_msg) 89 | if pti: 90 | success = 1 91 | elif pti == False: 92 | if sh == "Blocked": 93 | blocked=1 94 | elif sh == "Deleted": 95 | deleted = 1 96 | elif sh == "Error": 97 | failed = 1 98 | done = 1 99 | return success, blocked, deleted, failed, done 100 | -------------------------------------------------------------------------------- /database/connections_mdb.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import pymongo 4 | from info import DATABASE_URI, DATABASE_NAME 5 | import logging 6 | logger = logging.getLogger(__name__) 7 | logger.setLevel(logging.ERROR) 8 | 9 | myclient = pymongo.MongoClient(DATABASE_URI) 10 | mydb = myclient[DATABASE_NAME] 11 | mycol = mydb['CONNECTION'] 12 | 13 | 14 | async def add_connection(group_id, user_id): 15 | query = mycol.find_one( 16 | { "_id": user_id }, 17 | { "_id": 0, "active_group": 0 } 18 | ) 19 | if query is not None: 20 | group_ids = [x["group_id"] for x in query["group_details"]] 21 | if group_id in group_ids: 22 | return False 23 | 24 | group_details = { 25 | "group_id" : group_id 26 | } 27 | 28 | data = { 29 | '_id': user_id, 30 | 'group_details' : [group_details], 31 | 'active_group' : group_id, 32 | } 33 | 34 | if mycol.count_documents( {"_id": user_id} ) == 0: 35 | try: 36 | mycol.insert_one(data) 37 | return True 38 | except: 39 | logger.exception('Some error occurred!', exc_info=True) 40 | 41 | else: 42 | try: 43 | mycol.update_one( 44 | {'_id': user_id}, 45 | { 46 | "$push": {"group_details": group_details}, 47 | "$set": {"active_group" : group_id} 48 | } 49 | ) 50 | return True 51 | except: 52 | logger.exception('Some error occurred!', exc_info=True) 53 | 54 | 55 | async def active_connection(user_id): 56 | 57 | query = mycol.find_one( 58 | { "_id": user_id }, 59 | { "_id": 0, "group_details": 0 } 60 | ) 61 | if not query: 62 | return None 63 | 64 | group_id = query['active_group'] 65 | return int(group_id) if group_id != None else None 66 | 67 | 68 | async def all_connections(user_id): 69 | query = mycol.find_one( 70 | { "_id": user_id }, 71 | { "_id": 0, "active_group": 0 } 72 | ) 73 | if query is not None: 74 | return [x["group_id"] for x in query["group_details"]] 75 | else: 76 | return None 77 | 78 | 79 | async def if_active(user_id, group_id): 80 | query = mycol.find_one( 81 | { "_id": user_id }, 82 | { "_id": 0, "group_details": 0 } 83 | ) 84 | return query is not None and query['active_group'] == group_id 85 | 86 | 87 | async def make_active(user_id, group_id): 88 | update = mycol.update_one( 89 | {'_id': user_id}, 90 | {"$set": {"active_group" : group_id}} 91 | ) 92 | return update.modified_count != 0 93 | 94 | 95 | async def make_inactive(user_id): 96 | update = mycol.update_one( 97 | {'_id': user_id}, 98 | {"$set": {"active_group" : None}} 99 | ) 100 | return update.modified_count != 0 101 | 102 | 103 | async def delete_connection(user_id, group_id): 104 | 105 | try: 106 | update = mycol.update_one( 107 | {"_id": user_id}, 108 | {"$pull" : { "group_details" : {"group_id":group_id} } } 109 | ) 110 | if update.modified_count == 0: 111 | return False 112 | query = mycol.find_one( 113 | { "_id": user_id }, 114 | { "_id": 0 } 115 | ) 116 | if len(query["group_details"]) >= 1: 117 | if query['active_group'] == group_id: 118 | prvs_group_id = query["group_details"][len(query["group_details"]) - 1]["group_id"] 119 | 120 | mycol.update_one( 121 | {'_id': user_id}, 122 | {"$set": {"active_group" : prvs_group_id}} 123 | ) 124 | else: 125 | mycol.update_one( 126 | {'_id': user_id}, 127 | {"$set": {"active_group" : None}} 128 | ) 129 | return True 130 | except Exception as e: 131 | logger.exception(f'Some error occurred! {e}', exc_info=True) 132 | return False 133 | 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Safari-Filter-Bot Logo 3 |

4 |

5 | 𝑺𝒂𝒇𝒂𝒓𝒊-𝑭𝒊𝒍𝒕𝒆𝒓-𝑩𝒐𝒕 6 |

7 | 8 | ![Typing SVG](https://readme-typing-svg.herokuapp.com/?lines=𝑊𝑒𝑙𝑐𝑜𝑚𝑒+𝑆𝑎𝑓𝑎𝑟𝑖-𝐹𝑖𝑙𝑡𝑒𝑟-𝐵𝑜𝑡!;𝐶𝑟𝑒𝑎𝑡𝑒𝑑+𝑏𝑦+𝑆𝑎𝑓𝑎𝑟𝑖𝑑𝑒𝑣𝑣!;𝐴+𝑝𝑜𝑤𝑒𝑟𝑓𝑢𝑙+⚡+𝑠𝑢𝑝𝑒𝑟+𝑎𝑛𝑑+𝑐𝑜𝑜𝑙+𝑓𝑒𝑎𝑡𝑢𝑟𝑒𝑠+𝑠𝑒𝑒+𝑡ℎ𝑒+𝑓𝑒𝑎𝑡𝑢𝑟𝑒𝑠!) 9 |

10 | ## 𝐹𝑒𝑎𝑡𝑢𝑟𝑒𝑠 11 | ♦ 𝐼𝑀𝐷𝐵 𝑇𝑒𝑚𝑝𝑙𝑎𝑡𝑒 𝑆𝑒𝑡 12 | ♦ 𝑃𝑟𝑒𝐷𝑉𝐷 𝑎𝑛𝑑 𝐶𝑎𝑚𝑅𝑖𝑝 𝐷𝑒𝑙𝑒𝑡𝑒 𝑀𝑜𝑑𝑒 13 | ♦ 𝑀𝑢𝑙𝑡𝑖𝑝𝑙𝑒 𝐹𝑖𝑙𝑒 𝐷𝑒𝑙𝑒𝑡𝑖𝑜𝑛 14 | ♦ 𝑆𝑒𝑡𝑡𝑖𝑛𝑔𝑠 𝑀𝑒𝑛𝑢 15 | ♦ 𝐹𝑜𝑟𝑐𝑒 𝑆𝑢𝑏𝑠𝑐𝑟𝑖𝑝𝑡𝑖𝑜𝑛 16 | ♦ 𝑊𝑒𝑙𝑐𝑜𝑚𝑒 𝑀𝑒𝑠𝑠𝑎𝑔𝑒 17 | ♦ 𝐴𝑢𝑡𝑜𝑚𝑎𝑡𝑖𝑐 𝐹𝑖𝑙𝑒 𝐹𝑖𝑙𝑡𝑒𝑟𝑖𝑛𝑔 18 | ♦ 𝑇𝑒𝑥𝑡 𝑜𝑟 𝐵𝑢𝑡𝑡𝑜𝑛 𝐹𝑖𝑙𝑡𝑒𝑟 19 | ♦ 𝐼𝑀𝐷𝐵 20 | ♦ 𝐴𝑑𝑚𝑖𝑛 𝐶𝑜𝑚𝑚𝑎𝑛𝑑𝑠 21 | ♦ 𝑈𝑠𝑒𝑟 𝐵𝑟𝑜𝑎𝑑𝑐𝑎𝑠𝑡 22 | ♦ 𝐺𝑟𝑜𝑢𝑝 𝐵𝑟𝑜𝑎𝑑𝑐𝑎𝑠𝑡 23 | ♦ 𝐼𝑀𝐷𝐵 𝑠𝑒𝑎𝑟𝑐ℎ 24 | ♦ 𝑅𝑎𝑛𝑑𝑜𝑚 𝑝𝑖𝑐𝑠 25 | ♦ 𝑖𝑑𝑠 𝑎𝑛𝑑 𝑈𝑠𝑒𝑟 𝑖𝑛𝑓𝑜 26 | ♦ 𝑆𝑡𝑎𝑡𝑠 27 | ♦ 𝑈𝑠𝑒𝑟𝑠 28 | ♦ 𝐶ℎ𝑎𝑡𝑠 29 | ♦ 𝑈𝑠𝑒𝑟 𝐵𝑎𝑛 30 | ♦ 𝑈𝑠𝑒𝑟 𝑈𝑛𝑏𝑎𝑛 31 | ♦ 𝐶ℎ𝑎𝑡 𝐿𝑒𝑎𝑣𝑒 32 | ♦ 𝐶ℎ𝑎𝑡 𝐷𝑖𝑠𝑎𝑏𝑙𝑒 33 | ♦ 𝐶ℎ𝑎𝑛𝑛𝑒𝑙 34 | ♦ 𝑆𝑝𝑒𝑙𝑙𝑖𝑛𝑔 𝐶ℎ𝑒𝑐𝑘 𝐹𝑒𝑎𝑡𝑢𝑟𝑒 35 | ♦ 𝐴𝑢𝑡𝑜 𝐷𝑒𝑙𝑒𝑡𝑒 36 | ╔═══════ 𝑬𝒙𝒕𝒓𝒂 𝑨𝒅𝒅𝒆𝒅 𝑭𝒆𝒂𝒕𝒖𝒓𝒆𝒔 ═══════╗ 37 | 38 | 🔷 𝑮𝒓𝒐𝒖𝒑 𝑽𝒆𝒓𝒊𝒇𝒚 𝑺𝒚𝒔𝒕𝒆𝒎 39 | 🔷 𝑺𝒕𝒓𝒆𝒂𝒎𝒊𝒏𝒈 𝑺𝒉𝒐𝒓𝒏𝒆𝒓 𝑳𝒊𝒏𝒌 40 | 🔷 𝑨𝒊 𝑺𝒑𝒆𝒍𝒍 𝑪𝒉𝒆𝒄𝒌 41 | 🔷 𝑪𝒉𝒂𝒏𝒏𝒆𝒍 𝑻𝒂𝒈 𝑹𝒆𝒎𝒐𝒗𝒆 42 | 🔷 𝑭𝒖𝒍𝒍 𝑪𝒖𝒔𝒕𝒐𝒎𝒊𝒛𝒃𝒍𝒆 𝑩𝒐𝒕 𝑰𝒏 𝑮𝒓𝒐𝒖𝒑 43 | 🔷 𝑨𝒅𝒅 𝑷𝒓𝒆𝒎𝒊𝒖𝒎 𝑼𝒔𝒆𝒓𝒔 𝑰𝒏 𝑪𝒐𝒎𝒎𝒂𝒏𝒅 44 | 🔷 𝑹𝒆𝒎𝒐𝒗𝒆 𝑼𝒏𝒔𝒆𝒂𝒔𝒆𝒚 𝑼𝒔𝒆𝒍𝒆𝒔𝒔 𝑾𝒐𝒓𝒅 45 | 🔷 𝑨𝒏𝒅 𝑮𝒓𝒐𝒖𝒑 𝑪𝒐𝒏𝒕𝒓𝒐𝒍 𝑭𝒆𝒂𝒕𝒖𝒓𝒆𝒔 46 | 47 | 𝙅𝙤𝙞𝙣 𝘽𝙤𝙩 𝙐𝙥𝙙𝙖𝙩𝙚𝙨 𝘾𝙝𝙖𝙣𝙣𝙚𝙡 𝐁𝐨𝐭 𝐔𝐩𝐝𝐚𝐭𝐞 𝐈𝐧𝐟𝐨𝐫𝐦𝐚𝐭𝐢𝐨𝐧. 48 | 49 | ## 𝐶𝑜𝑚𝑚𝑎𝑛𝑑𝑠 50 | 51 | ## Variables 52 | 53 | ### Required Variables 54 | * `BOT_TOKEN`: Create a bot using [@BotFather](https://telegram.dog/BotFather), and get the Telegram API token. 55 | * `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) 56 | * `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) 57 | * `CHANNELS`: Username or ID of channel or group. Separate multiple IDs by space 58 | * `ADMINS`: Username or ID of Admin. Separate multiple Admins by space 59 | * `DATABASE_URI`: [mongoDB](https://www.mongodb.com) URI. Get this value from [mongoDB](https://www.mongodb.com). For more help watch this [video](https://youtu.be/1G1XwEOnxxo) 60 | * `DATABASE_NAME`: Name of the database in [mongoDB](https://www.mongodb.com). For more help watch this [video](https://youtu.be/1G1XwEOnxxo) 61 | * `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. 62 | * `FQDN` : Online Streaming: fill app server link without [https://] & [/] 63 | * `BIN_CHANNEL` : Streaming stats 64 | 65 | 66 |
Deploy To Heroku 67 |

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

73 |
74 |
Deploy To Heroku Via Bot 75 |

76 |
77 | 78 | Deploy Via Heroku Bot 79 | 80 |

81 |
82 | 83 |
Deploy To Koyeb 84 |
85 | The fastest way to deploy the application is to click the Deploy to Koyeb button below. 86 |
87 |
88 | 89 | [![Deploy to Koyeb](https://www.koyeb.com/static/images/deploy/button.svg)](https://app.koyeb.com/deploy?type=git&repository=github.com/Safaridevv/SuperBot&branch=main) 90 |
91 | 92 |
Deploy To Render 93 |
94 | 95 | Use these commands: 96 |
97 |
98 | • Build Command: pip3 install -U -r requirements.txt 99 |
100 |
101 | • Start Command: python3 bot.py 102 |
103 |
104 | Go to https://uptimerobot.com/ and add a monitor to keep your bot alive. 105 |
106 |
107 | Use these settings when adding a monitor:
108 |
109 |
110 | render template 111 |
112 |
113 | Click on the below button to deploy directly to render ↓ 114 |
115 |
116 | 117 | Deploy to Render 118 | 119 |
120 | 121 |
Deploy To VPS 122 |

123 |

124 | git clone https://github.com/Joelkb/DQ-The-File-Donor
125 | # Install Packages
126 | pip3 install -U -r requirements.txt
127 | Edit info.py with variables as given below then run bot
128 | python3 bot.py
129 | 
130 |

131 |
132 | 133 |
134 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/Request.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from fuzzywuzzy import process 4 | from imdb import IMDb 5 | from utils import temp 6 | from info import REQ_CHANNEL, GRP_LNK 7 | from pyrogram import Client, filters 8 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 9 | from database.ia_filterdb import get_search_results, get_all_files 10 | 11 | imdb = IMDb() 12 | 13 | async def ai_spell_check(chat_id, wrong_name): 14 | try: 15 | async def search_movie(wrong_name): 16 | search_results = imdb.search_movie(wrong_name) 17 | movie_list = [movie['title'] for movie in search_results] 18 | return movie_list 19 | 20 | movie_list = await search_movie(wrong_name) 21 | 22 | if not movie_list: 23 | return None 24 | 25 | for _ in range(5): 26 | closest_match = process.extractOne(wrong_name, movie_list) 27 | 28 | if not closest_match or closest_match[1] <= 80: 29 | return None 30 | 31 | movie = closest_match[0] 32 | files, offset, total_results = await get_search_results(chat_id=chat_id, query=movie) 33 | 34 | if files: 35 | return movie 36 | 37 | movie_list.remove(movie) 38 | 39 | return None 40 | 41 | except Exception as e: 42 | print(f"Error in ai_spell_check: {e}") 43 | return None 44 | 45 | 46 | @Client.on_message(filters.command(["request", "Request"]) & filters.private | filters.regex("#request") | filters.regex("#Request")) 47 | async def requests(client, message): 48 | search = message.text 49 | requested_movie = search.replace("/request", "").replace("/Request", "").strip() 50 | user_id = message.from_user.id 51 | 52 | if not requested_movie: 53 | await message.reply_text("🙅 (फिल्म रिक्वेस्ट करने के लिए कृपया फिल्म का नाम और साल साथ में लिखें\nकुछ इस तरह 👇\n/request Pushpa 2021") 54 | return 55 | 56 | files, offset, total_results = await get_search_results(chat_id=message.chat.id, query=requested_movie) 57 | 58 | if files: 59 | file_name = files[0]['file_name'] 60 | await message.reply_text(f"🎥 {file_name}\n\nआपने जो मूवी रिक्वेस्ट की है वो ग्रुप में उपलब्ध हैं\n\nग्रुप लिंक = {GRP_LNK}") 61 | else: 62 | closest_movie = await ai_spell_check(chat_id=message.chat.id, wrong_name=requested_movie) 63 | if closest_movie: 64 | files, offset, total_results = await get_search_results(chat_id=message.chat.id, query=closest_movie) 65 | if files: 66 | file_name = files[0]['file_name'] 67 | await message.reply_text(f"🎥 {file_name}\n\nआपने जो मूवी रिक्वेस्ट की है वो ग्रुप में उपलब्ध हैं\n\nग्रुप लिंक = {GRP_LNK}") 68 | else: 69 | await message.reply_text(f"✅ आपकी फिल्म {closest_movie} हमारे एडमिन के पास भेज दिया गया है.\n\n🚀 जैसे ही फिल्म अपलोड होती हैं हम आपको मैसेज देंगे.\n\n📌 ध्यान दे - एडमिन अपने काम में व्यस्त हो सकते है इसलिए फिल्म अपलोड होने में टाइम लग सकता हैं") 70 | await client.send_message( 71 | REQ_CHANNEL, 72 | f"☏ #𝙍𝙀𝙌𝙐𝙀𝙎𝙏𝙀𝘿_𝘾𝙊𝙉𝙏𝙀𝙉𝙏 ☎︎\n\nʙᴏᴛ - {temp.B_NAME}\nɴᴀᴍᴇ - {message.from_user.mention} ({message.from_user.id})\nRᴇǫᴜᴇꜱᴛ - {closest_movie}", 73 | reply_markup=InlineKeyboardMarkup( 74 | [[ 75 | InlineKeyboardButton('ɴᴏᴛ ʀᴇʟᴇᴀsᴇ 📅', callback_data=f"not_release:{user_id}:{requested_movie}"), 76 | InlineKeyboardButton('ɴᴏᴛ ᴀᴠᴀɪʟᴀʙʟᴇ 🙅', callback_data=f"not_available:{user_id}:{requested_movie}") 77 | ],[ 78 | InlineKeyboardButton('ᴜᴘʟᴏᴀᴅᴇᴅ ✅', callback_data=f"uploaded:{user_id}:{requested_movie}") 79 | ],[ 80 | InlineKeyboardButton('ɪɴᴠᴀʟɪᴅ ғᴏʀᴍᴀᴛ🙅', callback_data=f"series:{user_id}:{requested_movie}"), 81 | InlineKeyboardButton('sᴇʟʟ ᴍɪsᴛᴇᴋ✍️', callback_data=f"spelling_error:{user_id}:{requested_movie}") 82 | ],[ 83 | InlineKeyboardButton('⦉ ᴄʟᴏsᴇ ⦊', callback_data=f"close_data")] 84 | ]) 85 | ) 86 | else: 87 | await message.reply_text(f"✅ आपकी फिल्म {requested_movie} हमारे एडमिन के पास भेज दिया गया है.\n\n🚀 जैसे ही फिल्म अपलोड होती हैं हम आपको मैसेज देंगे.\n\n📌 ध्यान दे - एडमिन अपने काम में व्यस्त हो सकते है इसलिए फिल्म अपलोड होने में टाइम लग सकता हैं") 88 | await client.send_message( 89 | REQ_CHANNEL, 90 | f"📝 #REQUESTED_CONTENT 📝\n\nʙᴏᴛ - {temp.B_NAME}\nɴᴀᴍᴇ - {message.from_user.mention} ({message.from_user.id})\nRᴇǫᴜᴇꜱᴛ - {requested_movie}", 91 | reply_markup=InlineKeyboardMarkup( 92 | [[ 93 | InlineKeyboardButton('ɴᴏᴛ ʀᴇʟᴇᴀsᴇ 📅', callback_data=f"not_release:{user_id}:{requested_movie}"), 94 | InlineKeyboardButton('ɴᴏᴛ ᴀᴠᴀɪʟᴀʙʟᴇ 🙅', callback_data=f"not_available:{user_id}:{requested_movie}") 95 | ],[ 96 | InlineKeyboardButton('ᴜᴘʟᴏᴀᴅᴇᴅ ✅', callback_data=f"uploaded:{user_id}:{requested_movie}") 97 | ],[ 98 | InlineKeyboardButton('ɪɴᴠᴀʟɪᴅ ғᴏʀᴍᴀᴛ🙅', callback_data=f"series:{user_id}:{requested_movie}"), 99 | InlineKeyboardButton('sᴇʟʟ ᴍɪsᴛᴇᴋ✍️', callback_data=f"spelling_error:{user_id}:{requested_movie}") 100 | ],[ 101 | InlineKeyboardButton('⦉ ᴄʟᴏsᴇ ⦊', callback_data=f"close_data")] 102 | ]) 103 | ) 104 | -------------------------------------------------------------------------------- /plugins/channel.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from pyrogram import Client, filters, enums 4 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 5 | from info import CHANNELS, POST_CHANNELS 6 | from database.ia_filterdb import save_file, get_file_details 7 | from utils import get_poster, get_size, temp 8 | from os import environ 9 | import logging 10 | import re 11 | 12 | collected_files = [] 13 | post_active = False 14 | 15 | media_filter = filters.document | filters.video | filters.audio 16 | 17 | 18 | @Client.on_message(filters.chat(CHANNELS) & media_filter) 19 | async def media(bot, message): 20 | global post_active, collected_files 21 | 22 | language_map = { 23 | "hin": "Hindi", 24 | "eng": "English", 25 | "en": "English", 26 | "tel": "Telugu", 27 | "tam": "Tamil", 28 | "jap": "Japanese", 29 | "mar": "Marathi", 30 | "guj": "Gujarati", 31 | "Pun": "Punjabi", 32 | "Hindi": "Hindi", 33 | "English": "English", 34 | "Telugu": "Telugu", 35 | "Tamil": "Tamil", 36 | "Japanese": "Japanese", 37 | "Marathi": "Marathi", 38 | "Gujarati": "Gujarati", 39 | "Punjabi": "Punjabi" 40 | 41 | } 42 | 43 | for file_type in ("document", "video", "audio"): 44 | media = getattr(message, file_type, None) 45 | if media is not None: 46 | break 47 | else: 48 | return 49 | 50 | media.file_type = file_type 51 | media.caption = message.caption 52 | success, file_id = await save_file(media) 53 | 54 | if success and file_id: 55 | file_details = await get_file_details(file_id) 56 | if file_details: 57 | file_id = file_details[0]['file_id'] 58 | 59 | if success and "post count" in (media.caption or "").lower(): 60 | post_active = True 61 | collected_files = [] 62 | 63 | if post_active: 64 | languages_in_caption = re.findall(r'\b(' + '|'.join(language_map.keys()) + r')\b', media.caption) 65 | full_languages = ", ".join(language_map[lang] for lang in languages_in_caption) 66 | updated_caption = f"{media.caption}\n\nLanguage: {full_languages}" 67 | collected_files.append((file_id, media.file_name.replace('_', ' '), updated_caption, media.file_size)) 68 | 69 | if success and "send post" in (media.caption or "").lower(): 70 | post_active = False 71 | 72 | if collected_files: 73 | imdb_info = None 74 | 75 | for file_id, file_name, caption, file_size in collected_files: 76 | size_text = get_size(file_size) 77 | file_url = f"📁 [{size_text}]👇\n{file_name}" 78 | 79 | if imdb_info is None: 80 | try: 81 | movie_name = caption.split('|')[0].strip() 82 | logging.info(f"Searching IMDb for: {movie_name}") 83 | imdb_info = await get_poster(movie_name) 84 | if not imdb_info: 85 | logging.error(f"IMDb information not found for: {movie_name}") 86 | return 87 | except Exception as e: 88 | logging.error(f"Error while fetching IMDb info: {str(e)}") 89 | return 90 | 91 | if imdb_info: 92 | title = imdb_info.get('title', 'N/A') 93 | rating = imdb_info.get('rating', 'N/A') 94 | genre = imdb_info.get('genres', 'N/A') 95 | description = imdb_info.get('plot', 'N/A') 96 | poster_url = imdb_info.get('poster', None) 97 | year = imdb_info.get('year', 'N/A') 98 | 99 | urls_text = "\n\n".join([f"📁 [{get_size(size)}]👇\n{file_name}" for file_id, file_name, caption, size in collected_files]) 100 | 101 | language_in_caption = caption.split("Language:")[-1].strip() 102 | final_caption = f"🏷 Title: {title}\n🎭 Genres: {genre}\n📆 Year: {year}\n🌟 Rating: {rating}\n🔊 Language: {language_in_caption}\n\n{urls_text}" 103 | 104 | for channel in POST_CHANNELS: 105 | if poster_url: 106 | try: 107 | await bot.send_photo( 108 | chat_id=channel, 109 | photo=poster_url, 110 | caption=final_caption, 111 | parse_mode=enums.ParseMode.HTML 112 | ) 113 | except Exception as e: 114 | logging.error(f"Error sending poster to channel {channel}: {str(e)}") 115 | await bot.send_message( 116 | chat_id=channel, 117 | text=final_caption, 118 | parse_mode=enums.ParseMode.HTML 119 | ) 120 | else: 121 | url_text = "\n\n".join([f"📁 [{get_size(size)}]👇\n{file_name}" for file_id, file_name, caption, size in collected_files]) 122 | captionn = f"#Information_Not_Available\n\nTotal Files: {len(collected_files)}\n\n{url_text}" 123 | await bot.send_message( 124 | chat_id=channel, 125 | text=captionn, 126 | parse_mode=enums.ParseMode.HTML 127 | ) 128 | collected_files = [] 129 | -------------------------------------------------------------------------------- /plugins/connection.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit. 3 | from pyrogram import filters, Client, enums 4 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 5 | from database.connections_mdb import add_connection, all_connections, if_active, delete_connection 6 | from info import ADMINS 7 | import logging 8 | 9 | logger = logging.getLogger(__name__) 10 | logger.setLevel(logging.ERROR) 11 | 12 | 13 | @Client.on_message((filters.private | filters.group) & filters.command('connect')) 14 | async def addconnection(client, message): 15 | userid = message.from_user.id if message.from_user else None 16 | if not userid: 17 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 18 | chat_type = message.chat.type 19 | 20 | if chat_type == enums.ChatType.PRIVATE: 21 | try: 22 | cmd, group_id = message.text.split(" ", 1) 23 | except: 24 | await message.reply_text( 25 | "Enter in correct format!\n\n" 26 | "/connect groupid\n\n" 27 | "Get your Group id by adding this bot to your group and use /id", 28 | quote=True 29 | ) 30 | return 31 | 32 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 33 | group_id = message.chat.id 34 | 35 | try: 36 | st = await client.get_chat_member(group_id, userid) 37 | if ( 38 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 39 | and st.status != enums.ChatMemberStatus.OWNER 40 | and userid not in ADMINS 41 | ): 42 | await message.reply_text("You should be an admin in Given group!", quote=True) 43 | return 44 | except Exception as e: 45 | logger.exception(e) 46 | await message.reply_text( 47 | "Invalid Group ID!\n\nIf correct, Make sure I'm present in your group!!", 48 | quote=True, 49 | ) 50 | 51 | return 52 | try: 53 | st = await client.get_chat_member(group_id, "me") 54 | if st.status == enums.ChatMemberStatus.ADMINISTRATOR: 55 | ttl = await client.get_chat(group_id) 56 | title = ttl.title 57 | 58 | addcon = await add_connection(str(group_id), str(userid)) 59 | if addcon: 60 | await message.reply_text( 61 | f"Successfully connected to **{title}**\nNow manage your group from my pm !", 62 | quote=True, 63 | parse_mode=enums.ParseMode.MARKDOWN 64 | ) 65 | if chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 66 | await client.send_message( 67 | userid, 68 | f"Connected to **{title}** !", 69 | parse_mode=enums.ParseMode.MARKDOWN 70 | ) 71 | else: 72 | await message.reply_text( 73 | "You're already connected to this chat!", 74 | quote=True 75 | ) 76 | else: 77 | await message.reply_text("Add me as an admin in group", quote=True) 78 | except Exception as e: 79 | logger.exception(e) 80 | await message.reply_text('Some error occurred! Try again later.', quote=True) 81 | return 82 | 83 | 84 | @Client.on_message((filters.private | filters.group) & filters.command('disconnect')) 85 | async def deleteconnection(client, message): 86 | userid = message.from_user.id if message.from_user else None 87 | if not userid: 88 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 89 | chat_type = message.chat.type 90 | 91 | if chat_type == enums.ChatType.PRIVATE: 92 | await message.reply_text("Run /connections to view or disconnect from groups!", quote=True) 93 | 94 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 95 | group_id = message.chat.id 96 | 97 | st = await client.get_chat_member(group_id, userid) 98 | if ( 99 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 100 | and st.status != enums.ChatMemberStatus.OWNER 101 | and str(userid) not in ADMINS 102 | ): 103 | return 104 | 105 | delcon = await delete_connection(str(userid), str(group_id)) 106 | if delcon: 107 | await message.reply_text("Successfully disconnected from this chat", quote=True) 108 | else: 109 | await message.reply_text("This chat isn't connected to me!\nDo /connect to connect.", quote=True) 110 | 111 | 112 | @Client.on_message(filters.private & filters.command(["connections"])) 113 | async def connections(client, message): 114 | userid = message.from_user.id 115 | 116 | groupids = await all_connections(str(userid)) 117 | if groupids is None: 118 | await message.reply_text( 119 | "There are no active connections!! Connect to some groups first.", 120 | quote=True 121 | ) 122 | return 123 | buttons = [] 124 | for groupid in groupids: 125 | try: 126 | ttl = await client.get_chat(int(groupid)) 127 | title = ttl.title 128 | active = await if_active(str(userid), str(groupid)) 129 | act = " - ACTIVE" if active else "" 130 | buttons.append( 131 | [ 132 | InlineKeyboardButton( 133 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}" 134 | ) 135 | ] 136 | ) 137 | except: 138 | pass 139 | if buttons: 140 | await message.reply_text( 141 | "Your connected group details ;\n\n", 142 | reply_markup=InlineKeyboardMarkup(buttons), 143 | quote=True 144 | ) 145 | else: 146 | await message.reply_text( 147 | "There are no active connections!! Connect to some groups first.", 148 | quote=True 149 | ) 150 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/getfile.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from utils import temp 4 | from utils import get_poster 5 | from info import POST_CHANNELS 6 | from googletrans import Translator 7 | from pyrogram import Client, filters, enums 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 9 | 10 | translator = Translator() 11 | 12 | async def get_hindi(plot): 13 | try: 14 | translated = translator.translate(plot, dest='hi') 15 | return translated.text 16 | except Exception as e: 17 | print(f"Translation Error: {e}") 18 | return plot 19 | 20 | @Client.on_message(filters.command('getfile')) 21 | async def getfile(client, message): 22 | try: 23 | query = message.text.split(" ", 1) 24 | if len(query) < 2: 25 | return await message.reply_text("Usage: /getfile \n\nExample: /getfile Money Heist") 26 | file_name = query[1].strip() 27 | movie_details = await get_poster(file_name) 28 | 29 | if not movie_details: 30 | return await message.reply_text(f"No results found for {file_name} on IMDB.") 31 | 32 | poster = movie_details.get('poster', None) 33 | movie_title = movie_details.get('title', 'N/A') 34 | rating = movie_details.get('rating', 'N/A') 35 | genres = movie_details.get('genres', 'N/A') 36 | plot = movie_details.get('plot', 'N/A') 37 | year = movie_details.get('year', 'N/A') 38 | hindi_plot = await get_hindi(plot) 39 | 40 | custom_link = f"https://t.me/{temp.U_NAME}?start=getfile-{file_name.replace(' ', '-').lower()}" 41 | safari_markup = InlineKeyboardMarkup([ 42 | [InlineKeyboardButton("Get File 📁", url=custom_link) 43 | ]]) 44 | reply_markup = InlineKeyboardMarkup([ 45 | [InlineKeyboardButton("Yes", callback_data=f"post_yes_{file_name}"), 46 | InlineKeyboardButton("No", callback_data=f"post_no_{file_name}")] 47 | ]) 48 | 49 | if poster: 50 | await message.reply_photo( 51 | poster, 52 | caption=( 53 | f"🔖Title: {movie_title}\n" 54 | f"🎬 Genres: {genres}\n" 55 | f"⭐️ Rating: {rating}/10\n" 56 | f"📆 Year: {year}\n\n" 57 | f"📕 Story: {hindi_plot}" 58 | ), 59 | reply_markup=safari_markup, 60 | parse_mode=enums.ParseMode.HTML, 61 | ) 62 | await message.reply_text("Do you want to post this content on POST_CAHNNELS ?", 63 | reply_markup=reply_markup) 64 | else: 65 | await message.reply_text( 66 | ( 67 | f"🔖Title: {movie_title}\n" 68 | f"🎬 Genres: {genres}\n" 69 | f"⭐️ Rating: {rating}/10\n" 70 | f"📆 Year: {year}\n\n" 71 | f"📕 Story: {hindi_plot}" 72 | ), 73 | reply_markup=safari_markup, 74 | parse_mode=enums.ParseMode.HTML, 75 | ) 76 | await message.reply_text("Do you want to post this content on POST_CAHNNEL ?", 77 | reply_markup=reply_markup) 78 | except Exception as e: 79 | await message.reply_text(f"Error: {str(e)}") 80 | 81 | @Client.on_callback_query(filters.regex(r'^post_(yes|no)_')) 82 | async def post_to_channels(client, callback_query): 83 | action, file_name = callback_query.data.split('_')[1], callback_query.data.split('_')[2] 84 | 85 | if action == "yes": 86 | movie_details = await get_poster(file_name) 87 | 88 | if not movie_details: 89 | return await callback_query.message.reply_text(f"No results found for {file_name} on IMDB.") 90 | 91 | poster = movie_details.get('poster', None) 92 | movie_title = movie_details.get('title', 'N/A') 93 | rating = movie_details.get('rating', 'N/A') 94 | genres = movie_details.get('genres', 'N/A') 95 | plot = movie_details.get('plot', 'N/A') 96 | year = movie_details.get('year', 'N/A') 97 | hindi_plot = await get_hindi(plot) 98 | 99 | custom_link = f"https://t.me/{temp.U_NAME}?start=getfile-{file_name.replace(' ', '-').lower()}" 100 | reply_markup = InlineKeyboardMarkup([ 101 | [InlineKeyboardButton("Get File 📁", url=custom_link) 102 | ]]) 103 | for channel_id in POST_CHANNELS: 104 | try: 105 | if poster: 106 | await client.send_photo( 107 | chat_id=channel_id, 108 | photo=poster, 109 | caption=( 110 | f"🔖Title: {movie_title}\n" 111 | f"🎬 Genres: {genres}\n" 112 | f"⭐️ Rating: {rating}/10\n" 113 | f"📆 Year: {year}\n\n" 114 | f"📕 Story: {hindi_plot}" 115 | ), 116 | reply_markup=reply_markup, 117 | parse_mode=enums.ParseMode.HTML 118 | ) 119 | else: 120 | await client.send_message( 121 | chat_id=channel_id, 122 | text=( 123 | f"🔖Title: {movie_title}\n" 124 | f"🎬 Genres: {genres}\n" 125 | f"⭐️ Rating: {rating}/10\n" 126 | f"📆 Year: {year}\n\n" 127 | f"📕 Story: {hindi_plot}" 128 | ), 129 | reply_markup=reply_markup, 130 | parse_mode=enums.ParseMode.HTML 131 | ) 132 | except Exception as e: 133 | await callback_query.message.reply_text(f"Error posting to channel {channel_id}: {str(e)}") 134 | 135 | await callback_query.message.edit_text("Movie details successfully posted to channels.") 136 | 137 | elif action == "no": 138 | await callback_query.message.edit_text("Movie details will not be posted to channels.") 139 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/Redeem.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import re 4 | import time 5 | import pytz 6 | import asyncio 7 | import logging 8 | import hashlib 9 | import random 10 | import string 11 | from os import environ 12 | from info import ADMINS, PREMIUM_LOGS 13 | from datetime import datetime, timedelta 14 | from pyrogram import Client, filters 15 | from database.users_chats_db import db 16 | 17 | 18 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 19 | 20 | 21 | def hash_code(code): 22 | return hashlib.sha256(code.encode()).hexdigest() 23 | 24 | async def generate_code(duration_str): 25 | code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10)) 26 | kolkata_tz = pytz.timezone("Asia/Kolkata") 27 | created_at = datetime.now(tz=kolkata_tz) 28 | 29 | await db.codes.insert_one({ 30 | "code_hash": hash_code(code), 31 | "duration": duration_str, 32 | "used": False, 33 | "created_at": created_at, 34 | "original_code": code 35 | }) 36 | return code 37 | 38 | async def parse_duration(duration_str): 39 | pattern = r'(\d+)\s*(minute|minutes|hour|hours|day|days|week|weeks|month|months)' 40 | match = re.match(pattern, duration_str.lower()) 41 | 42 | if not match: 43 | return None 44 | 45 | value, unit = match.groups() 46 | value = int(value) 47 | 48 | if "minute" in unit: 49 | return value * 60 50 | elif "hour" in unit: 51 | return value * 60 * 60 52 | elif "day" in unit: 53 | return value * 24 * 60 * 60 54 | elif "week" in unit: 55 | return value * 7 * 24 * 60 * 60 56 | elif "month" in unit: 57 | return value * 30 * 24 * 60 * 60 58 | 59 | return None 60 | 61 | @Client.on_message(filters.command("code") & filters.user(ADMINS)) 62 | async def generate_code_cmd(client, message): 63 | if len(message.command) == 2: 64 | duration_str = message.command[1] 65 | premium_duration_seconds = await parse_duration(duration_str) 66 | if premium_duration_seconds is not None: 67 | token = await generate_code(duration_str) 68 | await message.reply_text(f"✅ ᴄᴏᴅᴇ ɢᴇɴᴇʀᴀᴛᴇᴅ sᴜᴄᴄᴇssғᴜʟʟʏ ♻️\n\n🔑 ᴄᴏᴅᴇ: `{token}`\n⌛ Vᴀʟɪᴅɪᴛʏ: {duration_str}\n\n𝐔𝐬𝐚𝐠𝐞 : /redeem xxxxxxxxxx\n\n𝐍𝐨𝐭𝐞 : Oɴʟʏ Oɴᴇ Usᴇʀ Cᴀɴ Usᴇ") 69 | 70 | else: 71 | await message.reply_text("❌ ɪɴᴠᴀʟɪᴅ ᴅᴜʀᴀᴛɪᴏɴ ғᴏʀᴍᴀᴛ. ᴘʟᴇᴀsᴇ ᴇɴᴛᴇʀ ᴀ ᴠᴀʟɪᴅ ᴅᴜʀᴀᴛɪᴏɴ ʟɪᴋᴇ '1minute', '1hours', '1days', '1months', etc.") 72 | else: 73 | await message.reply_text("Usage: /code 1month") 74 | 75 | @Client.on_message(filters.command("redeem")) 76 | async def redeem_code_cmd(client, message): 77 | if len(message.command) == 2: 78 | code = message.command[1] 79 | user_id = message.from_user.id 80 | 81 | if not await db.has_premium_access(user_id): 82 | code_data = await db.codes.find_one({"code_hash": hash_code(code)}) 83 | if code_data: 84 | if code_data['used']: 85 | await message.reply_text(f"🚫 ᴛʜɪs ᴄᴏᴅᴇ ᴀʟʀᴇᴀᴅʏ ᴜsᴇᴅ 🚫.") 86 | return 87 | premium_duration_seconds = await parse_duration(code_data['duration']) 88 | if premium_duration_seconds is not None: 89 | new_expiry = datetime.now() + timedelta(seconds=premium_duration_seconds) 90 | user_data = {"id": user_id, "expiry_time": new_expiry} 91 | await db.update_user(user_data) 92 | await db.codes.update_one({"_id": code_data["_id"]}, {"$set": {"used": True, "user_id": user_id}}) 93 | expiry_str_in_ist = new_expiry.astimezone(pytz.timezone("Asia/Kolkata")).strftime("⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ: %d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ: %I:%M:%S %p") 94 | await message.reply_text(f"🎉 ᴄᴏᴅᴇ ʀᴇᴅᴇᴇᴍᴇᴅ sᴜᴄᴄᴇssғᴜʟʟʏ!\nᴏᴜ ɴᴏᴡ ʜᴀᴠᴇ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇss ᴜɴᴛɪʟ:\n\n✨ᴅᴜʀᴀᴛɪᴏɴ: {code_data['duration']}\n{expiry_str_in_ist}") 95 | else: 96 | await message.reply_text("🚫 ɪɴᴠᴀʟɪᴅ ᴅᴜʀᴀᴛɪᴏɴ ɪɴ ᴛʜᴇ ᴄᴏᴅᴇ.") 97 | else: 98 | await message.reply_text("🚫 ɪɴᴠᴀʟɪᴅ ᴏʀ ᴇxᴘɪʀᴇᴅ ᴄᴏᴅᴇ.") 99 | else: 100 | await message.reply_text("❌ ʏᴏᴜ ᴀʟʀᴇᴀᴅʏ ʜᴀᴠᴇ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇss.") 101 | else: 102 | await message.reply_text("Usage: /redeem ") 103 | 104 | @Client.on_message(filters.command("clearcodes") & filters.user(ADMINS)) 105 | async def clear_codes_cmd(client, message): 106 | result = await db.codes.delete_many({}) 107 | if result.deleted_count > 0: 108 | await message.reply_text(f"✅ ᴀʟʟ {result.deleted_count} ᴄᴏᴅᴇs ʜᴀᴠᴇ ʙᴇᴇɴ ʀᴇᴍᴏᴠᴇᴅ sᴜᴄᴄᴇssғᴜʟʟʏ.") 109 | else: 110 | await message.reply_text("⚠️ ɴᴏ ᴄᴏᴅᴇs ғᴏᴜɴᴅ ᴛʜᴀᴛ ᴄᴏᴜʟᴅ ʙᴇ ᴄʟᴇᴀʀᴇᴅ.") 111 | 112 | @Client.on_message(filters.command("allcodes") & filters.user(ADMINS)) 113 | async def all_codes_cmd(client, message): 114 | all_codes = await db.codes.find({}).to_list(length=None) 115 | if not all_codes: 116 | await message.reply_text("⚠️ ᴛʜᴇʀᴇ ᴀʀᴇ ɴᴏ ᴄᴏᴅᴇs ᴀᴠᴀɪʟᴀʙʟᴇ.") 117 | return 118 | 119 | codes_info = "📝 **ɢᴇɴᴇʀᴀᴛᴇᴅ ᴄᴏᴅᴇs ᴅᴇᴛᴀɪʟs:**\n\n" 120 | for code_data in all_codes: 121 | original_code = code_data.get("original_code", "Unknown") 122 | duration = code_data.get("duration", "Unknown") 123 | user_id = code_data.get("user_id") 124 | used = "Yes ✅" if code_data.get("used", False) else "No ⭕" 125 | created_at = code_data["created_at"].astimezone(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y %I:%M %p") 126 | if user_id: 127 | user = await client.get_users(user_id) 128 | user_name = user.first_name if user.first_name else "Unknown User" 129 | user_mention = f"[{user_name}](tg://user?id={user_id})" 130 | else: 131 | user_mention = "Not Redeemed" 132 | 133 | codes_info += f"**🔑 Code**: `{original_code}`\n" 134 | codes_info += f"**⌛ Duration**: {duration}\n" 135 | codes_info += f"**‼ Used**: {used}\n" 136 | codes_info += f"**🕓 Created At**: {created_at}\n" 137 | codes_info += f"**🙎 User ID**: {user_mention}\n\n" 138 | 139 | 140 | for chunk in [codes_info[i:i + 4096] for i in range(0, len(codes_info), 4096)]: 141 | await message.reply_text(chunk) 142 | -------------------------------------------------------------------------------- /SAFARI/route.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | import re 3 | import math 4 | import logging 5 | import secrets 6 | import time 7 | import mimetypes 8 | from aiohttp.http_exceptions import BadStatusLine 9 | from SAFARI.utils import multi_clients, work_loads, SafariBot 10 | from SAFARI.utils.exceptions import FIleNotFound, InvalidHash 11 | from SAFARI import StartTime, __version__ 12 | from SAFARI.utils.custom_dl import ByteStreamer 13 | from SAFARI.utils.time_format import get_readable_time 14 | from SAFARI.utils.render_template import render_page 15 | from info import * 16 | 17 | 18 | routes = web.RouteTableDef() 19 | 20 | home_template = """ 21 | 22 | 23 | 24 | 25 | 26 | Safaribotts 27 | 40 | 41 | 42 | Chatbot Image 43 | 44 |

Safaribotts

45 | 46 | 47 | """ 48 | 49 | @routes.get("/", allow_head=True) 50 | async def root_route_handler(request): 51 | return web.Response(text=home_template, content_type='text/html') 52 | 53 | 54 | @routes.get(r"/watch/{path:\S+}", allow_head=True) 55 | async def stream_handler(request: web.Request): 56 | try: 57 | path = request.match_info["path"] 58 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path) 59 | if match: 60 | secure_hash = match.group(1) 61 | id = int(match.group(2)) 62 | else: 63 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1)) 64 | secure_hash = request.rel_url.query.get("hash") 65 | return web.Response(text=await render_page(id, secure_hash), content_type='text/html') 66 | except InvalidHash as e: 67 | raise web.HTTPForbidden(text=e.message) 68 | except FIleNotFound as e: 69 | raise web.HTTPNotFound(text=e.message) 70 | except (AttributeError, BadStatusLine, ConnectionResetError): 71 | pass 72 | except Exception as e: 73 | logging.critical(e.with_traceback(None)) 74 | raise web.HTTPInternalServerError(text=str(e)) 75 | 76 | @routes.get(r"/{path:\S+}", allow_head=True) 77 | async def stream_handler(request: web.Request): 78 | try: 79 | path = request.match_info["path"] 80 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path) 81 | if match: 82 | secure_hash = match.group(1) 83 | id = int(match.group(2)) 84 | else: 85 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1)) 86 | secure_hash = request.rel_url.query.get("hash") 87 | return await media_streamer(request, id, secure_hash) 88 | except InvalidHash as e: 89 | raise web.HTTPForbidden(text=e.message) 90 | except FIleNotFound as e: 91 | raise web.HTTPNotFound(text=e.message) 92 | except (AttributeError, BadStatusLine, ConnectionResetError): 93 | pass 94 | except Exception as e: 95 | logging.critical(e.with_traceback(None)) 96 | raise web.HTTPInternalServerError(text=str(e)) 97 | 98 | class_cache = {} 99 | 100 | async def media_streamer(request: web.Request, id: int, secure_hash: str): 101 | range_header = request.headers.get("Range", 0) 102 | 103 | index = min(work_loads, key=work_loads.get) 104 | faster_client = multi_clients[index] 105 | 106 | if MULTI_CLIENT: 107 | logging.info(f"Client {index} is now serving {request.remote}") 108 | 109 | if faster_client in class_cache: 110 | tg_connect = class_cache[faster_client] 111 | logging.debug(f"Using cached ByteStreamer object for client {index}") 112 | else: 113 | logging.debug(f"Creating new ByteStreamer object for client {index}") 114 | tg_connect = ByteStreamer(faster_client) 115 | class_cache[faster_client] = tg_connect 116 | logging.debug("before calling get_file_properties") 117 | file_id = await tg_connect.get_file_properties(id) 118 | logging.debug("after calling get_file_properties") 119 | 120 | if file_id.unique_id[:6] != secure_hash: 121 | logging.debug(f"Invalid hash for message with ID {id}") 122 | raise InvalidHash 123 | 124 | file_size = file_id.file_size 125 | 126 | if range_header: 127 | from_bytes, until_bytes = range_header.replace("bytes=", "").split("-") 128 | from_bytes = int(from_bytes) 129 | until_bytes = int(until_bytes) if until_bytes else file_size - 1 130 | else: 131 | from_bytes = request.http_range.start or 0 132 | until_bytes = (request.http_range.stop or file_size) - 1 133 | 134 | if (until_bytes > file_size) or (from_bytes < 0) or (until_bytes < from_bytes): 135 | return web.Response( 136 | status=416, 137 | body="416: Range not satisfiable", 138 | headers={"Content-Range": f"bytes */{file_size}"}, 139 | ) 140 | 141 | chunk_size = 1024 * 1024 142 | until_bytes = min(until_bytes, file_size - 1) 143 | 144 | offset = from_bytes - (from_bytes % chunk_size) 145 | first_part_cut = from_bytes - offset 146 | last_part_cut = until_bytes % chunk_size + 1 147 | 148 | req_length = until_bytes - from_bytes + 1 149 | part_count = math.ceil(until_bytes / chunk_size) - math.floor(offset / chunk_size) 150 | body = tg_connect.yield_file( 151 | file_id, index, offset, first_part_cut, last_part_cut, part_count, chunk_size 152 | ) 153 | 154 | mime_type = file_id.mime_type 155 | file_name = file_id.file_name 156 | disposition = "attachment" 157 | 158 | if mime_type: 159 | if not file_name: 160 | try: 161 | file_name = f"{secrets.token_hex(2)}.{mime_type.split('/')[1]}" 162 | except (IndexError, AttributeError): 163 | file_name = f"{secrets.token_hex(2)}.unknown" 164 | else: 165 | if file_name: 166 | mime_type = mimetypes.guess_type(file_id.file_name) 167 | else: 168 | mime_type = "application/octet-stream" 169 | file_name = f"{secrets.token_hex(2)}.unknown" 170 | 171 | return web.Response( 172 | status=206 if range_header else 200, 173 | body=body, 174 | headers={ 175 | "Content-Type": f"{mime_type}", 176 | "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}", 177 | "Content-Length": str(req_length), 178 | "Content-Disposition": f'{disposition}; filename="{file_name}"', 179 | "Accept-Ranges": "bytes", 180 | }, 181 | ) 182 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/Group_Verify.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from pyrogram import Client, filters, enums 4 | from database.users_chats_db import db 5 | from utils import temp 6 | from info import ADMINS, GROUP_VERIFY_LOGS 7 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 8 | 9 | 10 | @Client.on_callback_query(filters.regex(r"^verify_group_")) 11 | async def verify_group_callback(client, query): 12 | data = query.data.split("_") 13 | chat_id = int(data[2]) 14 | group_info = await db.get_chat(chat_id) 15 | owner_id = group_info.get('owner_id', None) 16 | user = await client.get_users(owner_id) 17 | group_title = group_info.get('title', 'Unknown Group') 18 | total = await client.get_chat_members_count(chat_id) 19 | 20 | if not group_info: 21 | await query.answer("ɢʀᴏᴜᴘ ɴᴏᴛ ғᴏᴜɴᴅ!", show_alert=True) 22 | return 23 | if group_info.get('grp_link'): 24 | group_link = group_info['grp_link'] 25 | else: 26 | chat = await client.get_chat(chat_id) 27 | if chat.username: 28 | group_link = f"https://t.me/{chat.username}" 29 | else: 30 | try: 31 | invite_link = await client.create_chat_invite_link(chat_id) 32 | group_link = invite_link.invite_link 33 | except Exception as e: 34 | group_link = "No link available" 35 | if await db.rejected_group(chat_id): 36 | await db.un_rejected(chat_id) 37 | await db.verify_group(chat_id) 38 | await query.answer("ᴛʜᴇ ɢʀᴏᴜᴘ ʜᴀs ʙᴇᴇɴ ᴠᴇʀɪғɪᴇᴅ ✅", show_alert=True) 39 | 40 | await query.message.edit_text( 41 | f"𝑩𝒐𝒕: {temp.U_NAME}\n𝑮𝒓𝒐𝒖𝒑: {group_title}\n𝑰𝑫: {chat_id}\n𝑴𝒆𝒎𝒃𝒆𝒓𝒔: {total}\n𝑼𝒔𝒆𝒓: {user.mention}\n\nGʀᴏᴜᴘ Is Vᴇʀɪғɪᴇᴅ. ✅", 42 | reply_markup=InlineKeyboardMarkup( 43 | [[InlineKeyboardButton("Rᴇᴊᴇᴄᴛ ⛔", callback_data=f"rejected_group_{chat_id}")]] 44 | ) 45 | ) 46 | 47 | if owner_id: 48 | await client.send_message(chat_id=owner_id, text=f"#𝐕𝐞𝐫𝐢𝐟𝐲𝐞𝐝_𝐆𝐫𝐨𝐮𝐩\n\nGʀᴏᴜᴘ Nᴀᴍᴇ: {group_title}\nIᴅ: {chat_id}\n\nCᴏɴɢʀᴀᴛᴜʟᴀᴛɪᴏɴs Gʀᴏᴜᴘ Is Vᴇʀɪғɪᴇᴅ. ✅.") 49 | 50 | @Client.on_callback_query(filters.regex(r"^rejected_group_")) 51 | async def rejected_group_callback(client, query): 52 | data = query.data.split("_") 53 | chat_id = int(data[2]) 54 | group_info = await db.get_chat(chat_id) 55 | owner_id = group_info.get('owner_id', None) 56 | user = await client.get_users(owner_id) 57 | group_title = group_info.get('title', 'Unknown Group') 58 | total = await client.get_chat_members_count(chat_id) 59 | if not group_info: 60 | await query.answer("ɢʀᴏᴜᴘ ɴᴏᴛ ғᴏᴜɴᴅ!", show_alert=True) 61 | return 62 | if group_info.get('grp_link'): 63 | group_link = group_info['grp_link'] 64 | else: 65 | chat = await client.get_chat(chat_id) 66 | if chat.username: 67 | group_link = f"https://t.me/{chat.username}" 68 | else: 69 | try: 70 | invite_link = await client.create_chat_invite_link(chat_id) 71 | group_link = invite_link.invite_link 72 | except Exception as e: 73 | group_link = "No link available" 74 | await db.reject_group(chat_id) 75 | await query.answer("ᴛʜᴇ ɢʀᴏᴜᴘ ʜᴀs ʙᴇᴇɴ ʀᴇᴊᴇᴄᴛᴇᴅ ❌", show_alert=True) 76 | 77 | await query.message.edit_text(f"𝑩𝒐𝒕: {temp.U_NAME}\n𝑮𝒓𝒐𝒖𝒑: {group_title}\n𝑰𝑫: {chat_id}\n𝑴𝒆𝒎𝒃𝒆𝒓𝒔: {total}\n𝑼𝒔𝒆𝒓: {user.mention}\n\nRᴇᴊᴇᴄᴛᴇᴅ Gʀᴏᴜᴘ ❌", reply_markup=InlineKeyboardMarkup( 78 | [[InlineKeyboardButton("Tᴀᴘ Tᴏ Vᴇʀɪғʏ ✅", callback_data=f"verify_group_{chat_id}")]] 79 | )) 80 | if owner_id: 81 | await client.send_message(chat_id=owner_id, text=f"#𝐑𝐞𝐣𝐞𝐜𝐭_𝐆𝐫𝐨𝐮𝐩❌\n\nGʀᴏᴜᴘ Nᴀᴍᴇ: {group_title}\nIᴅ: {chat_id}\n\nʏᴏᴜʀ ɢʀᴏᴜᴘ ʜᴀs ʙᴇᴇɴ ʀᴇᴊᴇᴄᴛᴇᴅ\n\n ᴄᴏɴᴛᴀᴄᴛ ᴍʏ ᴀᴅᴍɪɴ: @Safaridev.") 82 | 83 | 84 | # Verify command to initiate the group verification 85 | @Client.on_message(filters.group & filters.command("verify")) 86 | async def grpp_verify(bot, message): 87 | user = await bot.get_chat_member(message.chat.id, message.from_user.id) 88 | total=await bot.get_chat_members_count(message.chat.id) 89 | owner_id = message.from_user.id 90 | group_link = message.chat.invite_link 91 | is_verified = await db.check_group_verification(message.chat.id) 92 | is_rejected = await db.rejected_group(message.chat.id) 93 | owner=user.status in [enums.ChatMemberStatus.ADMINISTRATOR, enums.ChatMemberStatus.OWNER] or str(message.from_user.id) in ADMINS 94 | if message.chat.username: 95 | group_link = f"https://t.me/{message.chat.username}" 96 | else: 97 | try: 98 | invite_link = await bot.create_chat_invite_link(message.chat.id) 99 | group_link = invite_link.invite_link 100 | except Exception as e: 101 | group_link = "No link available" 102 | if not is_rejected: 103 | if owner: 104 | if not is_verified: 105 | if not await db.get_chat(message.chat.id): 106 | await db.add_chat(message.chat.id, message.chat.title, owner_id) 107 | await bot.send_message( 108 | chat_id=GROUP_VERIFY_LOGS, 109 | text=f"#𝐕𝐞𝐫𝐢𝐟𝐲_𝐆𝐫𝐨𝐮𝐩\n\n𝑩𝒐𝒕: {temp.U_NAME}\n𝑮𝒓𝒐𝒖𝒑:- {message.chat.title}\n𝑰𝑫: {message.chat.id}\n𝑴𝒆𝒎𝒃𝒆𝒓𝒔:- {total}\n𝑼𝒔𝒆𝒓: {message.from_user.mention}", 110 | reply_markup=InlineKeyboardMarkup([ 111 | [InlineKeyboardButton("Tᴀᴘ Tᴏ Vᴇʀɪғʏ ✅", callback_data=f"verify_group_{message.chat.id}")], 112 | [InlineKeyboardButton("Rᴇᴊᴇᴄᴛ ⭕", callback_data=f"rejected_group_{message.chat.id}")]] 113 | ) 114 | ) 115 | await message.reply("ᴠᴇʀɪғʏ ʀᴇǫᴜᴇsᴛ sᴇɴᴛ ᴛᴏ ᴍʏ ᴀᴅᴍɪɴ, ᴘʟᴇᴀsᴇ ᴡᴀɪᴛ ғᴏʀ ᴛʜᴇ ᴄᴏɴғɪʀᴍᴀᴛɪᴏɴ.") 116 | else: 117 | await message.reply("Gʀᴏᴜᴘ Aʟʀᴇᴀᴅʏ Vᴇʀɪғɪᴇᴅ ✅") 118 | else: 119 | await message.reply_text( 120 | text=f"ᴜsᴇ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴏɴʟʏ ɢʀᴏᴜᴘ ᴀᴅᴍɪɴs", 121 | ) 122 | else: 123 | if owner: 124 | await message.reply_text(text=f" ʏᴏᴜʀ ɢʀᴏᴜᴘ ʜᴀs ʙᴇᴇɴ ʀᴇᴊᴇᴄᴛᴇᴅ ʙʏ ᴍʏ ᴀᴅᴍɪɴ.\n\nɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ɢᴇᴛ ᴛʜᴇ ɢʀᴏᴜᴘ ᴠᴇʀɪғɪᴇᴅ ᴛʜᴇɴ contact ᴛʜᴇ ᴀᴅᴍɪɴ. @Safaridev.") 125 | else: 126 | await message.reply("ᴜsᴇ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴏɴʟʏ ɢʀᴏᴜᴘ ᴀᴅᴍɪɴs") 127 | 128 | 129 | # Command to delete all saved groups and leave them 130 | @Client.on_message(filters.command("grp_delete") & filters.user(ADMINS)) 131 | async def delete_all_groups_command(bot, message): 132 | all_groups = await db.get_all_groups() 133 | for group in all_groups: 134 | try: 135 | await bot.send_message(group['id'], "The bot is now leaving this group as per the admin's command.") 136 | await bot.leave_chat(group['id']) 137 | except Exception as e: 138 | print(f"Failed to leave chat {group['id']}: {e}") 139 | await db.delete_all_groups() 140 | await message.reply_text("All saved groups have been deleted and bot has left all groups.") 141 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/features/font.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import os 4 | from .fotnt_string import Fonts 5 | from pyrogram import Client, filters 6 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 7 | 8 | 9 | @Client.on_message(filters.private & filters.command(["font"])) 10 | async def style_buttons(c, m, cb=False): 11 | buttons = [[ 12 | InlineKeyboardButton('𝚃𝚢𝚙𝚎𝚠𝚛𝚒𝚝𝚎𝚛', callback_data='style+typewriter'), 13 | InlineKeyboardButton('𝕆𝕦𝕥𝕝𝕚𝕟𝕖', callback_data='style+outline'), 14 | InlineKeyboardButton('𝐒𝐞𝐫𝐢𝐟', callback_data='style+serif'), 15 | ],[ 16 | InlineKeyboardButton('𝑺𝒆𝒓𝒊𝒇', callback_data='style+bold_cool'), 17 | InlineKeyboardButton('𝑆𝑒𝑟𝑖𝑓', callback_data='style+cool'), 18 | InlineKeyboardButton('Sᴍᴀʟʟ Cᴀᴘs', callback_data='style+small_cap'), 19 | ],[ 20 | InlineKeyboardButton('𝓈𝒸𝓇𝒾𝓅𝓉', callback_data='style+script'), 21 | InlineKeyboardButton('𝓼𝓬𝓻𝓲𝓹𝓽', callback_data='style+script_bolt'), 22 | InlineKeyboardButton('ᵗⁱⁿʸ', callback_data='style+tiny'), 23 | ],[ 24 | InlineKeyboardButton('ᑕOᗰIᑕ', callback_data='style+comic'), 25 | InlineKeyboardButton('𝗦𝗮𝗻𝘀', callback_data='style+sans'), 26 | InlineKeyboardButton('𝙎𝙖𝙣𝙨', callback_data='style+slant_sans'), 27 | ],[ 28 | InlineKeyboardButton('𝘚𝘢𝘯𝘴', callback_data='style+slant'), 29 | InlineKeyboardButton('𝖲𝖺𝗇𝗌', callback_data='style+sim'), 30 | InlineKeyboardButton('Ⓒ︎Ⓘ︎Ⓡ︎Ⓒ︎Ⓛ︎Ⓔ︎Ⓢ︎', callback_data='style+circles') 31 | ],[ 32 | InlineKeyboardButton('🅒︎🅘︎🅡︎🅒︎🅛︎🅔︎🅢︎', callback_data='style+circle_dark'), 33 | InlineKeyboardButton('𝔊𝔬𝔱𝔥𝔦𝔠', callback_data='style+gothic'), 34 | InlineKeyboardButton('𝕲𝖔𝖙𝖍𝖎𝖈', callback_data='style+gothic_bolt'), 35 | ],[ 36 | InlineKeyboardButton('C͜͡l͜͡o͜͡u͜͡d͜͡s͜͡', callback_data='style+cloud'), 37 | InlineKeyboardButton('H̆̈ă̈p̆̈p̆̈y̆̈', callback_data='style+happy'), 38 | InlineKeyboardButton('S̑̈ȃ̈d̑̈', callback_data='style+sad'), 39 | ],[ 40 | InlineKeyboardButton('Next ➡️', callback_data="nxt") 41 | ]] 42 | if not cb: 43 | if ' ' in m.text: 44 | title = m.text.split(" ", 1)[1] 45 | await m.reply_text(title, reply_markup=InlineKeyboardMarkup(buttons), reply_to_message_id=m.id) 46 | else: 47 | await m.reply_text(text="Ente Any Text Eg:- `/font [text]`") 48 | else: 49 | await m.answer() 50 | await m.message.edit_reply_markup(InlineKeyboardMarkup(buttons)) 51 | 52 | 53 | @Client.on_callback_query(filters.regex('^nxt')) 54 | async def nxt(c, m): 55 | if m.data == "nxt": 56 | buttons = [[ 57 | InlineKeyboardButton('🇸 🇵 🇪 🇨 🇮 🇦 🇱 ', callback_data='style+special'), 58 | InlineKeyboardButton('🅂🅀🅄🄰🅁🄴🅂', callback_data='style+squares'), 59 | InlineKeyboardButton('🆂︎🆀︎🆄︎🅰︎🆁︎🅴︎🆂︎', callback_data='style+squares_bold'), 60 | ],[ 61 | InlineKeyboardButton('ꪖꪀᦔꪖꪶꪊᥴ𝓲ꪖ', callback_data='style+andalucia'), 62 | InlineKeyboardButton('爪卂几ᘜ卂', callback_data='style+manga'), 63 | InlineKeyboardButton('S̾t̾i̾n̾k̾y̾', callback_data='style+stinky'), 64 | ],[ 65 | InlineKeyboardButton('B̥ͦu̥ͦb̥ͦb̥ͦl̥ͦe̥ͦs̥ͦ', callback_data='style+bubbles'), 66 | InlineKeyboardButton('U͟n͟d͟e͟r͟l͟i͟n͟e͟', callback_data='style+underline'), 67 | InlineKeyboardButton('꒒ꍏꀷꌩꌃꀎꁅ', callback_data='style+ladybug'), 68 | ],[ 69 | InlineKeyboardButton('R҉a҉y҉s҉', callback_data='style+rays'), 70 | InlineKeyboardButton('B҈i҈r҈d҈s҈', callback_data='style+birds'), 71 | InlineKeyboardButton('S̸l̸a̸s̸h̸', callback_data='style+slash'), 72 | ],[ 73 | InlineKeyboardButton('s⃠t⃠o⃠p⃠', callback_data='style+stop'), 74 | InlineKeyboardButton('S̺͆k̺͆y̺͆l̺͆i̺͆n̺͆e̺͆', callback_data='style+skyline'), 75 | InlineKeyboardButton('A͎r͎r͎o͎w͎s͎', callback_data='style+arrows'), 76 | ],[ 77 | InlineKeyboardButton('ዪሀክቿነ', callback_data='style+qvnes'), 78 | InlineKeyboardButton('S̶t̶r̶i̶k̶e̶', callback_data='style+strike'), 79 | InlineKeyboardButton('F༙r༙o༙z༙e༙n༙', callback_data='style+frozen') 80 | ],[ 81 | InlineKeyboardButton('⬅️ Back', callback_data='nxt+0') 82 | ]] 83 | await m.answer() 84 | await m.message.edit_reply_markup(InlineKeyboardMarkup(buttons)) 85 | else: 86 | await style_buttons(c, m, cb=True) 87 | 88 | 89 | @Client.on_callback_query(filters.regex('^style')) 90 | async def style(c, m): 91 | await m.answer() 92 | cmd, style = m.data.split('+') 93 | 94 | if style == 'typewriter': 95 | cls = Fonts.typewriter 96 | if style == 'outline': 97 | cls = Fonts.outline 98 | if style == 'serif': 99 | cls = Fonts.serief 100 | if style == 'bold_cool': 101 | cls = Fonts.bold_cool 102 | if style == 'cool': 103 | cls = Fonts.cool 104 | if style == 'small_cap': 105 | cls = Fonts.smallcap 106 | if style == 'script': 107 | cls = Fonts.script 108 | if style == 'script_bolt': 109 | cls = Fonts.bold_script 110 | if style == 'tiny': 111 | cls = Fonts.tiny 112 | if style == 'comic': 113 | cls = Fonts.comic 114 | if style == 'sans': 115 | cls = Fonts.san 116 | if style == 'slant_sans': 117 | cls = Fonts.slant_san 118 | if style == 'slant': 119 | cls = Fonts.slant 120 | if style == 'sim': 121 | cls = Fonts.sim 122 | if style == 'circles': 123 | cls = Fonts.circles 124 | if style == 'circle_dark': 125 | cls = Fonts.dark_circle 126 | if style == 'gothic': 127 | cls = Fonts.gothic 128 | if style == 'gothic_bolt': 129 | cls = Fonts.bold_gothic 130 | if style == 'cloud': 131 | cls = Fonts.cloud 132 | if style == 'happy': 133 | cls = Fonts.happy 134 | if style == 'sad': 135 | cls = Fonts.sad 136 | if style == 'special': 137 | cls = Fonts.special 138 | if style == 'squares': 139 | cls = Fonts.square 140 | if style == 'squares_bold': 141 | cls = Fonts.dark_square 142 | if style == 'andalucia': 143 | cls = Fonts.andalucia 144 | if style == 'manga': 145 | cls = Fonts.manga 146 | if style == 'stinky': 147 | cls = Fonts.stinky 148 | if style == 'bubbles': 149 | cls = Fonts.bubbles 150 | if style == 'underline': 151 | cls = Fonts.underline 152 | if style == 'ladybug': 153 | cls = Fonts.ladybug 154 | if style == 'rays': 155 | cls = Fonts.rays 156 | if style == 'birds': 157 | cls = Fonts.birds 158 | if style == 'slash': 159 | cls = Fonts.slash 160 | if style == 'stop': 161 | cls = Fonts.stop 162 | if style == 'skyline': 163 | cls = Fonts.skyline 164 | if style == 'arrows': 165 | cls = Fonts.arrows 166 | if style == 'qvnes': 167 | cls = Fonts.rvnes 168 | if style == 'strike': 169 | cls = Fonts.strike 170 | if style == 'frozen': 171 | cls = Fonts.frozen 172 | 173 | r, oldtxt = m.message.reply_to_message.text.split(None, 1) 174 | new_text = cls(oldtxt) 175 | try: 176 | await m.message.edit_text(f"`{new_text}`\n\n👆 Click To Copy", reply_markup=m.message.reply_markup) 177 | except Exception as e: 178 | print(e) 179 | -------------------------------------------------------------------------------- /database/ia_filterdb.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import logging 4 | from struct import pack 5 | import re 6 | import base64 7 | from pyrogram.file_id import FileId 8 | from pymongo.errors import DuplicateKeyError 9 | from umongo import Instance, Document, fields 10 | from motor.motor_asyncio import AsyncIOMotorClient 11 | from marshmallow.exceptions import ValidationError 12 | from info import DATABASE_URI, DATABASE_NAME, COLLECTION_NAME, USE_CAPTION_FILTER, MAX_B_TN 13 | from utils import get_settings, save_group_settings 14 | from fuzzywuzzy import process 15 | from Script import script 16 | 17 | # Set up logging 18 | logging.basicConfig(level=logging.INFO) 19 | 20 | logger = logging.getLogger(__name__) 21 | logger.setLevel(logging.INFO) 22 | 23 | 24 | client = AsyncIOMotorClient(DATABASE_URI) 25 | db = client[DATABASE_NAME] 26 | instance = Instance.from_db(db) 27 | 28 | @instance.register 29 | class Media(Document): 30 | file_id = fields.StrField(attribute='_id') 31 | file_ref = fields.StrField(allow_none=True) 32 | file_name = fields.StrField(required=True) 33 | file_size = fields.IntField(required=True) 34 | file_type = fields.StrField(allow_none=True) 35 | mime_type = fields.StrField(allow_none=True) 36 | caption = fields.StrField(allow_none=True) 37 | 38 | class Meta: 39 | indexes = ('$file_name', ) 40 | collection_name = COLLECTION_NAME 41 | 42 | 43 | async def save_file(media): 44 | """Save file in database""" 45 | 46 | # TODO: Find better way to get same file_id for same media to avoid duplicates 47 | file_id, file_ref = unpack_new_file_id(media.file_id) 48 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 49 | try: 50 | file = Media( 51 | file_id=file_id, 52 | file_ref=file_ref, 53 | file_name=file_name, 54 | file_size=media.file_size, 55 | file_type=media.file_type, 56 | mime_type=media.mime_type, 57 | caption=media.caption.html if media.caption else None, 58 | ) 59 | except ValidationError: 60 | logger.exception('Error occurred while saving file in database') 61 | return False, None 62 | else: 63 | try: 64 | await file.commit() 65 | except DuplicateKeyError: 66 | logger.warning( 67 | f'{getattr(media, "file_name", "NO_FILE")} is already saved in database' 68 | ) 69 | 70 | return False, file_id 71 | else: 72 | logger.info(f'{getattr(media, "file_name", "NO_FILE")} is saved to database') 73 | return True, file_id 74 | 75 | 76 | 77 | async def get_search_results(chat_id, query, file_type=None, max_results=10, offset=0, filter=False): 78 | """For given query return (results, next_offset)""" 79 | banned_words = script.BLACKLIST 80 | if chat_id is not None: 81 | settings = await get_settings(int(chat_id)) 82 | try: 83 | if settings['max_btn']: 84 | max_results = 10 85 | else: 86 | max_results = int(MAX_B_TN) 87 | except KeyError: 88 | await save_group_settings(int(chat_id), 'max_btn', False) 89 | settings = await get_settings(int(chat_id)) 90 | if settings['max_btn']: 91 | max_results = 10 92 | else: 93 | max_results = int(MAX_B_TN) 94 | query = query.strip() 95 | #if filter: 96 | #better ? 97 | #query = query.replace(' ', r'(\s|\.|\+|\-|_)') 98 | #raw_pattern = r'(\s|_|\-|\.|\+)' + query + r'(\s|_|\-|\.|\+)' 99 | if not query: 100 | raw_pattern = '.' 101 | elif ' ' not in query: 102 | raw_pattern = r'(\b|[\.\+\-_])' + query + r'(\b|[\.\+\-_])' 103 | else: 104 | raw_pattern = query.replace(' ', r'.*[\s\.\+\-_]') 105 | 106 | try: 107 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 108 | except: 109 | return [] 110 | 111 | if USE_CAPTION_FILTER: 112 | filter = {'$or': [{'file_name': regex}, {'caption': regex}]} 113 | else: 114 | filter = {'file_name': regex} 115 | 116 | if file_type: 117 | filter['file_type'] = file_type 118 | 119 | total_results = await Media.count_documents(filter) 120 | next_offset = offset + max_results 121 | 122 | if next_offset > total_results: 123 | next_offset = '' 124 | 125 | cursor = Media.find(filter) 126 | # Sort by recent 127 | cursor.sort('$natural', -1) 128 | # Slice files according to offset and max results 129 | cursor.skip(offset).limit(max_results) 130 | # Get list of files 131 | files = await cursor.to_list(length=max_results) 132 | for file in files: 133 | for banned_word in banned_words: 134 | # Case-insensitive replacement 135 | pattern = re.compile(re.escape(banned_word), re.IGNORECASE) 136 | file['file_name'] = pattern.sub('', file['file_name']).strip() 137 | 138 | return files, next_offset, total_results 139 | 140 | async def get_all_files(): 141 | cursor = Media.find() 142 | all_files = await cursor.to_list(length=10000) 143 | return [file['file_name'] for file in all_files] 144 | 145 | async def get_bad_files(query, file_type=None, filter=False): 146 | """For given query return (results, next_offset)""" 147 | query = query.strip() 148 | #if filter: 149 | #better ? 150 | #query = query.replace(' ', r'(\s|\.|\+|\-|_)') 151 | #raw_pattern = r'(\s|_|\-|\.|\+)' + query + r'(\s|_|\-|\.|\+)' 152 | if not query: 153 | raw_pattern = '.' 154 | elif ' ' not in query: 155 | raw_pattern = r'(\b|[\.\+\-_])' + query + r'(\b|[\.\+\-_])' 156 | else: 157 | raw_pattern = query.replace(' ', r'.*[\s\.\+\-_]') 158 | 159 | try: 160 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 161 | except: 162 | return [] 163 | 164 | if USE_CAPTION_FILTER: 165 | filter = {'$or': [{'file_name': regex}, {'caption': regex}]} 166 | else: 167 | filter = {'file_name': regex} 168 | 169 | if file_type: 170 | filter['file_type'] = file_type 171 | 172 | total_results = await Media.count_documents(filter) 173 | 174 | cursor = Media.find(filter) 175 | # Sort by recent 176 | cursor.sort('$natural', -1) 177 | # Get list of files 178 | files = await cursor.to_list(length=total_results) 179 | 180 | return files, total_results 181 | 182 | async def get_file_details(query): 183 | try: 184 | banned_words = script.BLACKLIST 185 | filter = {'file_id': query} 186 | cursor = Media.find(filter) 187 | filedetails = await cursor.to_list(length=1) 188 | if filedetails: 189 | file = filedetails[0] 190 | original_file_name = getattr(file, 'file_name', '') 191 | modified_file_name = original_file_name 192 | for banned_word in banned_words: 193 | pattern = re.compile(re.escape(banned_word), re.IGNORECASE) 194 | modified_file_name = pattern.sub('', modified_file_name).strip() 195 | if not modified_file_name: 196 | modified_file_name = "DefaultFileName" 197 | setattr(file, 'file_name', modified_file_name) 198 | return filedetails 199 | except Exception as e: 200 | logging.error("An error occurred:", exc_info=True) 201 | return None 202 | 203 | def encode_file_id(s: bytes) -> str: 204 | r = b"" 205 | n = 0 206 | 207 | for i in s + bytes([22]) + bytes([4]): 208 | if i == 0: 209 | n += 1 210 | else: 211 | if n: 212 | r += b"\x00" + bytes([n]) 213 | n = 0 214 | 215 | r += bytes([i]) 216 | 217 | return base64.urlsafe_b64encode(r).decode().rstrip("=") 218 | 219 | 220 | def encode_file_ref(file_ref: bytes) -> str: 221 | return base64.urlsafe_b64encode(file_ref).decode().rstrip("=") 222 | 223 | 224 | def unpack_new_file_id(new_file_id): 225 | """Return file_id, file_ref""" 226 | decoded = FileId.decode(new_file_id) 227 | file_id = encode_file_id( 228 | pack( 229 | "➲ First Name: {first}\n➲ Last Name: {last}\n➲ Username: {username}\n➲ Telegram ID: {user_id}\n➲ Data Centre: {dc_id}", 26 | quote=True 27 | ) 28 | 29 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 30 | _id = "" 31 | _id += ( 32 | "➲ Chat ID: " 33 | f"{message.chat.id}\n" 34 | ) 35 | if message.reply_to_message: 36 | _id += ( 37 | "➲ User ID: " 38 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n" 39 | "➲ Replied User ID: " 40 | f"{message.reply_to_message.from_user.id if message.reply_to_message.from_user else 'Anonymous'}\n" 41 | ) 42 | file_info = get_file_id(message.reply_to_message) 43 | else: 44 | _id += ( 45 | "➲ User ID: " 46 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n" 47 | ) 48 | file_info = get_file_id(message) 49 | if file_info: 50 | _id += ( 51 | f"{file_info.message_type}: " 52 | f"{file_info.file_id}\n" 53 | ) 54 | await message.reply_text( 55 | _id, 56 | quote=True 57 | ) 58 | 59 | @Client.on_message(filters.command(["info"])) 60 | async def who_is(client, message): 61 | # https://github.com/SpEcHiDe/PyroGramBot/blob/master/pyrobot/plugins/admemes/whois.py#L19 62 | status_message = await message.reply_text( 63 | "`Fetching user info...`" 64 | ) 65 | await status_message.edit( 66 | "`Processing user info...`" 67 | ) 68 | from_user = None 69 | from_user_id, _ = extract_user(message) 70 | try: 71 | from_user = await client.get_users(from_user_id) 72 | except Exception as error: 73 | await status_message.edit(str(error)) 74 | return 75 | if from_user is None: 76 | return await status_message.edit("no valid user_id / message specified") 77 | message_out_str = "" 78 | message_out_str += f"➲First Name: {from_user.first_name}\n" 79 | last_name = from_user.last_name or "None" 80 | message_out_str += f"➲Last Name: {last_name}\n" 81 | message_out_str += f"➲Telegram ID: {from_user.id}\n" 82 | username = from_user.username or "None" 83 | dc_id = from_user.dc_id or "[User Doesn't Have A Valid DP]" 84 | message_out_str += f"➲Data Centre: {dc_id}\n" 85 | message_out_str += f"➲User Name: @{username}\n" 86 | message_out_str += f"➲User 𝖫𝗂𝗇𝗄: Click Here\n" 87 | if message.chat.type in ((enums.ChatType.SUPERGROUP, enums.ChatType.CHANNEL)): 88 | try: 89 | chat_member_p = await message.chat.get_member(from_user.id) 90 | joined_date = ( 91 | chat_member_p.joined_date or datetime.now() 92 | ).strftime("%Y.%m.%d %H:%M:%S") 93 | message_out_str += ( 94 | "➲Joined this Chat on: " 95 | f"{joined_date}" 96 | "\n" 97 | ) 98 | except UserNotParticipant: 99 | pass 100 | chat_photo = from_user.photo 101 | if chat_photo: 102 | local_user_photo = await client.download_media( 103 | message=chat_photo.big_file_id 104 | ) 105 | buttons = [[ 106 | InlineKeyboardButton('🔐 Close', callback_data='close_data') 107 | ]] 108 | reply_markup = InlineKeyboardMarkup(buttons) 109 | await message.reply_photo( 110 | photo=local_user_photo, 111 | quote=True, 112 | reply_markup=reply_markup, 113 | caption=message_out_str, 114 | parse_mode=enums.ParseMode.HTML, 115 | disable_notification=True 116 | ) 117 | os.remove(local_user_photo) 118 | else: 119 | buttons = [[ 120 | InlineKeyboardButton('🔐 Close', callback_data='close_data') 121 | ]] 122 | reply_markup = InlineKeyboardMarkup(buttons) 123 | await message.reply_text( 124 | text=message_out_str, 125 | reply_markup=reply_markup, 126 | quote=True, 127 | parse_mode=enums.ParseMode.HTML, 128 | disable_notification=True 129 | ) 130 | await status_message.delete() 131 | 132 | @Client.on_message(filters.command(["imdb", 'search'])) 133 | async def imdb_search(client, message): 134 | if ' ' in message.text: 135 | k = await message.reply('Searching ImDB') 136 | r, title = message.text.split(None, 1) 137 | movies = await get_poster(title, bulk=True) 138 | if not movies: 139 | return await message.reply("No results Found") 140 | btn = [ 141 | [ 142 | InlineKeyboardButton( 143 | text=f"{movie.get('title')} - {movie.get('year')}", 144 | callback_data=f"imdb#{movie.movieID}", 145 | ) 146 | ] 147 | for movie in movies 148 | ] 149 | await k.edit('Here is what i found on IMDb', reply_markup=InlineKeyboardMarkup(btn)) 150 | else: 151 | await message.reply('Give me a movie / series Name') 152 | 153 | @Client.on_callback_query(filters.regex('^imdb')) 154 | async def imdb_callback(bot: Client, quer_y: CallbackQuery): 155 | i, movie = quer_y.data.split('#') 156 | imdb = await get_poster(query=movie, id=True) 157 | btn = [ 158 | [ 159 | InlineKeyboardButton( 160 | text=f"{imdb.get('title')}", 161 | url=imdb['url'], 162 | ) 163 | ] 164 | ] 165 | message = quer_y.message.reply_to_message or quer_y.message 166 | if imdb: 167 | caption = IMDB_TEMPLATE.format( 168 | query = imdb['title'], 169 | title = imdb['title'], 170 | votes = imdb['votes'], 171 | aka = imdb["aka"], 172 | seasons = imdb["seasons"], 173 | box_office = imdb['box_office'], 174 | localized_title = imdb['localized_title'], 175 | kind = imdb['kind'], 176 | imdb_id = imdb["imdb_id"], 177 | cast = imdb["cast"], 178 | runtime = imdb["runtime"], 179 | countries = imdb["countries"], 180 | certificates = imdb["certificates"], 181 | languages = imdb["languages"], 182 | director = imdb["director"], 183 | writer = imdb["writer"], 184 | producer = imdb["producer"], 185 | composer = imdb["composer"], 186 | cinematographer = imdb["cinematographer"], 187 | music_team = imdb["music_team"], 188 | distributors = imdb["distributors"], 189 | release_date = imdb['release_date'], 190 | year = imdb['year'], 191 | genres = imdb['genres'], 192 | poster = imdb['poster'], 193 | plot = imdb['plot'], 194 | rating = imdb['rating'], 195 | url = imdb['url'], 196 | **locals() 197 | ) 198 | else: 199 | caption = "No Results" 200 | if imdb.get('poster'): 201 | try: 202 | await quer_y.message.reply_photo(photo=imdb['poster'], caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 203 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty): 204 | pic = imdb.get('poster') 205 | poster = pic.replace('.jpg', "._V1_UX360.jpg") 206 | await quer_y.message.reply_photo(photo=poster, caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 207 | except Exception as e: 208 | logger.exception(e) 209 | await quer_y.message.reply(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 210 | await quer_y.message.delete() 211 | else: 212 | await quer_y.message.edit(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 213 | await quer_y.answer() 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /plugins/Dev_Feature/Premium.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from datetime import timedelta, datetime, time 4 | import pytz 5 | from Script import script 6 | from asyncio import sleep 7 | from info import ADMINS, PREMIUM_LOGS, OWNER_USER_NAME, PREMIUM_PIC 8 | from utils import get_seconds 9 | from database.users_chats_db import db 10 | from pyrogram import Client, filters 11 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong 12 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 13 | 14 | async def check_expired_premium(client): 15 | while 1: 16 | data = await db.get_expired(datetime.now()) 17 | 18 | for user in data: 19 | user_id = user["id"] 20 | await db.remove_premium_access(user_id) 21 | try: 22 | user = await client.get_users(user_id) 23 | try: 24 | await client.send_message( 25 | chat_id=user_id, 26 | text=f"Hᴇʏ Tʜᴇʀᴇ {user.mention} 👋\n\nʏᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇss ʜᴀs ᴇxᴘɪʀᴇᴅ ❗\nᴛʜᴀɴᴋ ʏᴏᴜ ꜰᴏʀ ᴜsɪɴɢ ᴏᴜʀ sᴇʀᴠɪᴄᴇ.\n\nɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ᴛᴀᴋᴇ ᴛʜᴇ ᴘʀᴇᴍɪᴜᴍ ᴀɢᴀɪɴ, ᴛʜᴇɴ ᴄʟɪᴄᴋ ᴏɴ ᴛʜᴇ /plans ꜰᴏʀ ᴛʜᴇ ᴅᴇᴛᴀɪʟs ᴏꜰ ᴛʜᴇ ᴘʟᴀɴs.") 27 | except: 28 | pass 29 | await client.send_message( 30 | PREMIUM_LOGS, 31 | text=f"#PREMIUM_EXPIRED\n\nUsᴇʀ : {user.mention}\nUsᴇʀ Iᴅ : {user_id}" 32 | ) 33 | except Exception as e: 34 | pass 35 | await sleep(0.5) 36 | await sleep(1) 37 | 38 | @Client.on_message(filters.command("remove_premium") & filters.user(ADMINS)) 39 | async def remove_premium(client, message): 40 | if len(message.command) == 2: 41 | user_id = int(message.command[1]) # Convert the user_id to integer 42 | user = await client.get_users(user_id) 43 | if await db.remove_premium_access(user_id): 44 | await message.reply_text("ᴜꜱᴇʀ ʀᴇᴍᴏᴠᴇᴅ ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ !") 45 | await client.send_message( 46 | chat_id=user_id, 47 | text=f"ʜᴇʏ {user.mention},\n\nʏᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇss ʜᴀs ʙᴇᴇɴ ʀᴇᴍᴏᴠᴇᴅ.\nᴛʜᴀɴᴋ ʏᴏᴜ ꜰᴏʀ ᴜsɪɴɢ ᴏᴜʀ sᴇʀᴠɪᴄᴇ 😊\nᴄʟɪᴄᴋ ᴏɴ /plans ᴛᴏ ᴄʜᴇᴄᴋ ᴏᴜᴛ ᴏᴛʜᴇʀ ᴘʟᴀɴꜱ." 48 | ) 49 | else: 50 | await message.reply_text("ᴜɴᴀʙʟᴇ ᴛᴏ ʀᴇᴍᴏᴠᴇ ᴜꜱᴇᴅ !\nᴀʀᴇ ʏᴏᴜ ꜱᴜʀᴇ, ɪᴛ ᴡᴀꜱ ᴀ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀ ɪᴅ ?") 51 | else: 52 | await message.reply_text("ᴜꜱᴀɢᴇ : /remove_premium user_id") 53 | 54 | @Client.on_message(filters.command("myplan")) 55 | async def myplan(client, message): 56 | user = message.from_user.mention 57 | user_id = message.from_user.id 58 | data = await db.get_user(message.from_user.id) # Convert the user_id to integer 59 | if data and data.get("expiry_time"): 60 | expiry = data.get("expiry_time") 61 | expiry_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")) 62 | expiry_str_in_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : %I:%M:%S %p") 63 | current_time = datetime.now(pytz.timezone("Asia/Kolkata")) 64 | time_left = expiry_ist - current_time 65 | 66 | days = time_left.days 67 | hours, remainder = divmod(time_left.seconds, 3600) 68 | minutes, seconds = divmod(remainder, 60) 69 | 70 | # Format time left as a string 71 | time_left_str = f"{days} ᴅᴀʏꜱ, {hours} ʜᴏᴜʀꜱ, {minutes} ᴍɪɴᴜᴛᴇꜱ" 72 | await message.reply_text(f"⚜️ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀ ᴅᴀᴛᴀ :\n\n👤 ᴜꜱᴇʀ : {user}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏰ ᴛɪᴍᴇ ʟᴇꜰᴛ : {time_left_str}\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}") 73 | else: 74 | await message.reply_text(f"ʜᴇʏ {user},\n\nʏᴏᴜ ᴅᴏ ɴᴏᴛ ʜᴀᴠᴇ ᴀɴʏ ᴀᴄᴛɪᴠᴇ ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴs, ɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ᴛᴀᴋᴇ ᴘʀᴇᴍɪᴜᴍ ᴛʜᴇɴ ᴄʟɪᴄᴋ ᴏɴ ʙᴇʟᴏᴡ ʙᴜᴛᴛᴏɴ 👇", 75 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("💸 ᴄʜᴇᴄᴋᴏᴜᴛ ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴꜱ 💸", callback_data='premium_pm')]])) 76 | 77 | @Client.on_message(filters.command("get_premium") & filters.user(ADMINS)) 78 | async def get_premium(client, message): 79 | if len(message.command) == 2: 80 | user_id = int(message.command[1]) 81 | user = await client.get_users(user_id) 82 | data = await db.get_user(user_id) # Convert the user_id to integer 83 | if data and data.get("expiry_time"): 84 | expiry = data.get("expiry_time") 85 | expiry_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")) 86 | expiry_str_in_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : %I:%M:%S %p") 87 | # Calculate time difference 88 | current_time = datetime.now(pytz.timezone("Asia/Kolkata")) 89 | time_left = expiry_ist - current_time 90 | 91 | # Calculate days, hours, and minutes 92 | days = time_left.days 93 | hours, remainder = divmod(time_left.seconds, 3600) 94 | minutes, seconds = divmod(remainder, 60) 95 | 96 | # Format time left as a string 97 | time_left_str = f"{days} days, {hours} hours, {minutes} minutes" 98 | await message.reply_text(f"⚜️ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀ ᴅᴀᴛᴀ :\n\n👤 ᴜꜱᴇʀ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏰ ᴛɪᴍᴇ ʟᴇꜰᴛ : {time_left_str}\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}") 99 | else: 100 | await message.reply_text("ɴᴏ ᴀɴʏ ᴘʀᴇᴍɪᴜᴍ ᴅᴀᴛᴀ ᴏꜰ ᴛʜᴇ ᴡᴀꜱ ꜰᴏᴜɴᴅ ɪɴ ᴅᴀᴛᴀʙᴀꜱᴇ !") 101 | else: 102 | await message.reply_text("ᴜꜱᴀɢᴇ : /get_premium user_id") 103 | 104 | @Client.on_message(filters.command("add_premium") & filters.user(ADMINS)) 105 | async def give_premium_cmd_handler(client, message): 106 | if len(message.command) == 4: 107 | time_zone = datetime.now(pytz.timezone("Asia/Kolkata")) 108 | current_time = time_zone.strftime("%d-%m-%Y\n⏱️ ᴊᴏɪɴɪɴɢ ᴛɪᴍᴇ : %I:%M:%S %p") 109 | user_id = int(message.command[1]) # Convert the user_id to integer 110 | user = await client.get_users(user_id) 111 | time = message.command[2]+" "+message.command[3] 112 | seconds = await get_seconds(time) 113 | if seconds > 0: 114 | expiry_time = datetime.now() + timedelta(seconds=seconds) 115 | user_data = {"id": user_id, "expiry_time": expiry_time} # Using "id" instead of "user_id" 116 | await db.update_user(user_data) # Use the update_user method to update or insert user data 117 | data = await db.get_user(user_id) 118 | expiry = data.get("expiry_time") 119 | expiry_str_in_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : %I:%M:%S %p") 120 | await message.reply_text(f"ᴘʀᴇᴍɪᴜᴍ ᴀᴅᴅᴇᴅ ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ✅\n\n👤 ᴜꜱᴇʀ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}", disable_web_page_preview=True) 121 | await client.send_message( 122 | chat_id=user_id, 123 | text=f"👋 ʜᴇʏ {user.mention},\nᴛʜᴀɴᴋ ʏᴏᴜ ꜰᴏʀ ᴘᴜʀᴄʜᴀꜱɪɴɢ ᴘʀᴇᴍɪᴜᴍ.\nᴇɴᴊᴏʏ !! ✨🎉\n\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}", disable_web_page_preview=True 124 | ) 125 | await client.send_message(PREMIUM_LOGS, text=f"#Added_Premium\n\n👤 ᴜꜱᴇʀ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}", disable_web_page_preview=True) 126 | 127 | else: 128 | await message.reply_text("Invalid time format. Please use '1 day for days', '1 hour for hours', or '1 min for minutes', or '1 month for months' or '1 year for year'") 129 | else: 130 | await message.reply_text("Usage : /add_premium user_id time (e.g., '1 day for days', '1 hour for hours', or '1 min for minutes', or '1 month for months' or '1 year for year')") 131 | 132 | @Client.on_message(filters.command("premium_users") & filters.user(ADMINS)) 133 | async def premium_user(client, message): 134 | aa = await message.reply_text("ꜰᴇᴛᴄʜɪɴɢ...") 135 | new = f"⚜️ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀꜱ ʟɪꜱᴛ :\n\n" 136 | user_count = 1 137 | users = await db.get_all_users() 138 | async for user in users: 139 | data = await db.get_user(user['id']) 140 | if data and data.get("expiry_time"): 141 | expiry = data.get("expiry_time") 142 | expiry_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")) 143 | expiry_str_in_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : %I:%M:%S %p") 144 | current_time = datetime.now(pytz.timezone("Asia/Kolkata")) 145 | time_left = expiry_ist - current_time 146 | days = time_left.days 147 | hours, remainder = divmod(time_left.seconds, 3600) 148 | minutes, seconds = divmod(remainder, 60) 149 | time_left_str = f"{days} days, {hours} hours, {minutes} minutes" 150 | new += f"{user_count}. {(await client.get_users(user['id'])).mention}\n👤 ᴜꜱᴇʀ ɪᴅ : {user['id']}\n⏳ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}\n⏰ ᴛɪᴍᴇ ʟᴇꜰᴛ : {time_left_str}\n" 151 | user_count += 1 152 | else: 153 | pass 154 | try: 155 | await aa.edit_text(new) 156 | except MessageTooLong: 157 | with open('usersplan.txt', 'w+') as outfile: 158 | outfile.write(new) 159 | await message.reply_document('usersplan.txt', caption="Paid Users:") 160 | 161 | 162 | @Client.on_message(filters.command("plans")) 163 | async def plan(client, message): 164 | user_id = message.from_user.id 165 | users = message.from_user.mention 166 | btn = [[ 167 | InlineKeyboardButton("🔲 Qʀ ", callback_data='qr_info'), 168 | InlineKeyboardButton("💳 Uᴘɪ ", callback_data='upi_info')], 169 | [InlineKeyboardButton("❌ ᴄʟᴏꜱᴇ ❌", callback_data="close_data") 170 | ]] 171 | await message.reply_photo(photo=(PREMIUM_PIC), caption=script.PREMIUM_CMD, reply_markup=InlineKeyboardMarkup(btn)) 172 | 173 | # This code has been modified by @Safaridev 174 | # Please do not remove this credit 175 | -------------------------------------------------------------------------------- /SAFARI/utils/custom_dl.py: -------------------------------------------------------------------------------- 1 | import math 2 | import asyncio 3 | import logging 4 | from info import * 5 | from typing import Dict, Union 6 | from SAFARI.utils import work_loads 7 | from pyrogram import Client, utils, raw 8 | from SAFARI.utils.file_properties import get_file_ids 9 | from pyrogram.session import Session, Auth 10 | from pyrogram.errors import AuthBytesInvalid 11 | from SAFARI.utils.exceptions import FIleNotFound 12 | from pyrogram.file_id import FileId, FileType, ThumbnailSource 13 | 14 | 15 | class ByteStreamer: 16 | def __init__(self, client: Client): 17 | """A custom class that holds the cache of a specific client and class functions. 18 | attributes: 19 | client: the client that the cache is for. 20 | cached_file_ids: a dict of cached file IDs. 21 | cached_file_properties: a dict of cached file properties. 22 | 23 | functions: 24 | generate_file_properties: returns the properties for a media of a specific message contained in Tuple. 25 | generate_media_session: returns the media session for the DC that contains the media file. 26 | yield_file: yield a file from telegram servers for streaming. 27 | 28 | This is a modified version of the 29 | Thanks to Eyaadh 30 | """ 31 | self.clean_timer = 30 * 60 32 | self.client: Client = client 33 | self.cached_file_ids: Dict[int, FileId] = {} 34 | asyncio.create_task(self.clean_cache()) 35 | 36 | async def get_file_properties(self, id: int) -> FileId: 37 | """ 38 | Returns the properties of a media of a specific message in a FIleId class. 39 | if the properties are cached, then it'll return the cached results. 40 | or it'll generate the properties from the Message ID and cache them. 41 | """ 42 | if id not in self.cached_file_ids: 43 | await self.generate_file_properties(id) 44 | logging.debug(f"Cached file properties for message with ID {id}") 45 | return self.cached_file_ids[id] 46 | 47 | async def generate_file_properties(self, id: int) -> FileId: 48 | """ 49 | Generates the properties of a media file on a specific message. 50 | returns ths properties in a FIleId class. 51 | """ 52 | file_id = await get_file_ids(self.client, BIN_CHANNEL, id) 53 | logging.debug(f"Generated file ID and Unique ID for message with ID {id}") 54 | if not file_id: 55 | logging.debug(f"Message with ID {id} not found") 56 | raise FIleNotFound 57 | self.cached_file_ids[id] = file_id 58 | logging.debug(f"Cached media message with ID {id}") 59 | return self.cached_file_ids[id] 60 | 61 | async def generate_media_session(self, client: Client, file_id: FileId) -> Session: 62 | """ 63 | Generates the media session for the DC that contains the media file. 64 | This is required for getting the bytes from Telegram servers. 65 | """ 66 | 67 | media_session = client.media_sessions.get(file_id.dc_id, None) 68 | 69 | if media_session is None: 70 | if file_id.dc_id != await client.storage.dc_id(): 71 | media_session = Session( 72 | client, 73 | file_id.dc_id, 74 | await Auth( 75 | client, file_id.dc_id, await client.storage.test_mode() 76 | ).create(), 77 | await client.storage.test_mode(), 78 | is_media=True, 79 | ) 80 | await media_session.start() 81 | 82 | for _ in range(6): 83 | exported_auth = await client.invoke( 84 | raw.functions.auth.ExportAuthorization(dc_id=file_id.dc_id) 85 | ) 86 | 87 | try: 88 | await media_session.send( 89 | raw.functions.auth.ImportAuthorization( 90 | id=exported_auth.id, bytes=exported_auth.bytes 91 | ) 92 | ) 93 | break 94 | except AuthBytesInvalid: 95 | logging.debug( 96 | f"Invalid authorization bytes for DC {file_id.dc_id}" 97 | ) 98 | continue 99 | else: 100 | await media_session.stop() 101 | raise AuthBytesInvalid 102 | else: 103 | media_session = Session( 104 | client, 105 | file_id.dc_id, 106 | await client.storage.auth_key(), 107 | await client.storage.test_mode(), 108 | is_media=True, 109 | ) 110 | await media_session.start() 111 | logging.debug(f"Created media session for DC {file_id.dc_id}") 112 | client.media_sessions[file_id.dc_id] = media_session 113 | else: 114 | logging.debug(f"Using cached media session for DC {file_id.dc_id}") 115 | return media_session 116 | 117 | 118 | @staticmethod 119 | async def get_location(file_id: FileId) -> Union[raw.types.InputPhotoFileLocation, 120 | raw.types.InputDocumentFileLocation, 121 | raw.types.InputPeerPhotoFileLocation,]: 122 | """ 123 | Returns the file location for the media file. 124 | """ 125 | file_type = file_id.file_type 126 | 127 | if file_type == FileType.CHAT_PHOTO: 128 | if file_id.chat_id > 0: 129 | peer = raw.types.InputPeerUser( 130 | user_id=file_id.chat_id, access_hash=file_id.chat_access_hash 131 | ) 132 | else: 133 | if file_id.chat_access_hash == 0: 134 | peer = raw.types.InputPeerChat(chat_id=-file_id.chat_id) 135 | else: 136 | peer = raw.types.InputPeerChannel( 137 | channel_id=utils.get_channel_id(file_id.chat_id), 138 | access_hash=file_id.chat_access_hash, 139 | ) 140 | 141 | location = raw.types.InputPeerPhotoFileLocation( 142 | peer=peer, 143 | volume_id=file_id.volume_id, 144 | local_id=file_id.local_id, 145 | big=file_id.thumbnail_source == ThumbnailSource.CHAT_PHOTO_BIG, 146 | ) 147 | elif file_type == FileType.PHOTO: 148 | location = raw.types.InputPhotoFileLocation( 149 | id=file_id.media_id, 150 | access_hash=file_id.access_hash, 151 | file_reference=file_id.file_reference, 152 | thumb_size=file_id.thumbnail_size, 153 | ) 154 | else: 155 | location = raw.types.InputDocumentFileLocation( 156 | id=file_id.media_id, 157 | access_hash=file_id.access_hash, 158 | file_reference=file_id.file_reference, 159 | thumb_size=file_id.thumbnail_size, 160 | ) 161 | return location 162 | 163 | async def yield_file( 164 | self, 165 | file_id: FileId, 166 | index: int, 167 | offset: int, 168 | first_part_cut: int, 169 | last_part_cut: int, 170 | part_count: int, 171 | chunk_size: int, 172 | ) -> Union[str, None]: 173 | """ 174 | Custom generator that yields the bytes of the media file. 175 | Modded from 176 | Thanks to Eyaadh 177 | """ 178 | client = self.client 179 | work_loads[index] += 1 180 | logging.debug(f"Starting to yielding file with client {index}.") 181 | media_session = await self.generate_media_session(client, file_id) 182 | 183 | current_part = 1 184 | location = await self.get_location(file_id) 185 | 186 | try: 187 | r = await media_session.send( 188 | raw.functions.upload.GetFile( 189 | location=location, offset=offset, limit=chunk_size 190 | ), 191 | ) 192 | if isinstance(r, raw.types.upload.File): 193 | while True: 194 | chunk = r.bytes 195 | if not chunk: 196 | break 197 | elif part_count == 1: 198 | yield chunk[first_part_cut:last_part_cut] 199 | elif current_part == 1: 200 | yield chunk[first_part_cut:] 201 | elif current_part == part_count: 202 | yield chunk[:last_part_cut] 203 | else: 204 | yield chunk 205 | 206 | current_part += 1 207 | offset += chunk_size 208 | 209 | if current_part > part_count: 210 | break 211 | 212 | r = await media_session.send( 213 | raw.functions.upload.GetFile( 214 | location=location, offset=offset, limit=chunk_size 215 | ), 216 | ) 217 | except (TimeoutError, AttributeError): 218 | pass 219 | finally: 220 | logging.debug("Finished yielding file with {current_part} parts.") 221 | work_loads[index] -= 1 222 | 223 | 224 | async def clean_cache(self) -> None: 225 | """ 226 | function to clean the cache to reduce memory usage 227 | """ 228 | while True: 229 | await asyncio.sleep(self.clean_timer) 230 | self.cached_file_ids.clear() 231 | logging.debug("Cleaned the cache") 232 | -------------------------------------------------------------------------------- /SAFARI/template/req.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{file_name}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 34 |
35 |
36 | WELCOME 37 | CHANNELS 38 | 39 | LET'S TALK 40 |
41 |
42 | 43 |
44 |
45 |
46 | 48 |
49 |
50 | 51 | 52 |

{{file_name}}

53 |
54 |
55 | 57 | 59 | 62 | 64 | 66 | 69 | 72 |
73 | 74 |
75 |
76 |
77 |
78 |
79 |

WELCOME TO OUR STREAMING PAGE

80 |

81 | We're 82 | thrilled to have you here. 83 | Get ready for an 84 | amazing experience 85 | filled with entertainment, fun, and surprises. 86 | Grab 87 | your snacks, sit back, and enjoy the show! 88 |

89 |
90 | 117 |
118 | 119 |

we can tal'k for your support and you can report through 120 | telegram

121 | 124 |
125 |
126 |
127 |
128 |
129 |
130 | 136 | 137 |
138 |

139 | Welcome to our online streaming platform! Our website allows users to generate streamable links for 140 | various files using Telegram bots. Please note that we are not responsible for the content shared or 141 | streamed through our service. Users are encouraged to respect copyright laws and adhere to our 142 | community 143 | guidelines. Enjoy easy, hassle-free file streaming. 144 |

145 |
146 |
147 | 158 |
159 |
160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 177 | 178 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /plugins/p_ttishow.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | from pyrogram import Client, filters, enums 4 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery 5 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong, PeerIdInvalid 6 | from info import ADMINS, LOG_CHANNEL, SUPPORT_CHAT, MELCOW_NEW_USERS, WELCOME_VID, CHNL_LNK, GRP_LNK 7 | from database.users_chats_db import db 8 | from database.ia_filterdb import Media 9 | from utils import get_size, temp, get_settings 10 | from Script import script 11 | from pyrogram.errors import ChatAdminRequired 12 | import asyncio 13 | 14 | 15 | @Client.on_message(filters.new_chat_members & filters.group) 16 | async def save_group(bot, message): 17 | safaridev = [u.id for u in message.new_chat_members] 18 | if temp.ME in safaridev: 19 | if not await db.get_chat(message.chat.id): 20 | total=await bot.get_chat_members_count(message.chat.id) 21 | saf = message.from_user.mention if message.from_user else "Anonymous" 22 | await bot.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(temp.B_NAME, message.chat.title, message.chat.id, total, saf)) 23 | await db.add_chat(message.chat.id, message.chat.title, message.from_user.id) 24 | if message.chat.id in temp.BANNED_CHATS: 25 | # Inspired from a boat of a banana tree 26 | buttons = [[ 27 | InlineKeyboardButton('Support', url=GRP_NLK) 28 | ]] 29 | reply_markup=InlineKeyboardMarkup(buttons) 30 | k = await message.reply( 31 | text='CHAT NOT ALLOWED 🐞\n\nMy admins has restricted me from working here ! If you want to know more about it contact support..', 32 | reply_markup=reply_markup, 33 | ) 34 | 35 | try: 36 | await k.pin() 37 | except: 38 | pass 39 | await bot.leave_chat(message.chat.id) 40 | return 41 | 42 | 43 | await message.reply_text( 44 | text=f"ᴛʜᴀɴᴋʏᴏᴜ ғᴏʀ ᴀᴅᴅɪɴɢ ᴍᴇ ɪɴ {message.chat.title} ɢʀᴏᴜᴘ ❣️\n\nɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ᴛᴀᴋᴇ ᴀ ᴍᴏᴠɪᴇ ɪɴ ᴛʜɪs ɢʀᴏᴜᴘ,\n\nᴛʜᴇɴ ғɪʀsᴛ ʏᴏᴜ ʜᴀᴠᴇ ᴛᴏ ᴠᴇʀɪғʏ ᴛʜᴇ ɢʀᴏᴜᴘ.\n\nᴠᴇʀɪғʏ ᴛʜᴇ ɢʀᴏᴜᴘ ᴡɪᴛʜ /verify ᴄᴏᴍᴍᴀɴᴅ.." 45 | ) 46 | else: 47 | settings = await get_settings(message.chat.id) 48 | if settings["welcome"]: 49 | for u in message.new_chat_members: 50 | if (temp.MELCOW).get('welcome') is not None: 51 | try: 52 | await (temp.MELCOW['welcome']).delete() 53 | except: 54 | pass 55 | temp.MELCOW['welcome'] = await message.reply_video( 56 | video=WELCOME_VID, 57 | caption=(script.MELCOW_ENG.format(u.mention, message.chat.title)), 58 | parse_mode=enums.ParseMode.HTML 59 | ) 60 | await message.delete() 61 | if settings["auto_delete"]: 62 | await asyncio.sleep(600) 63 | await (temp.MELCOW['welcome']).delete() 64 | 65 | 66 | 67 | 68 | 69 | @Client.on_message(filters.command('leave') & filters.user(ADMINS)) 70 | async def leave_a_chat(bot, message): 71 | if len(message.command) == 1: 72 | return await message.reply('Give me a chat id') 73 | chat = message.command[1] 74 | try: 75 | chat = int(chat) 76 | except: 77 | chat = chat 78 | try: 79 | buttons = [[ 80 | InlineKeyboardButton('Support', url=f'https://t.me/{SUPPORT_CHAT}') 81 | ]] 82 | reply_markup=InlineKeyboardMarkup(buttons) 83 | await bot.send_message( 84 | chat_id=chat, 85 | 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.', 86 | reply_markup=reply_markup, 87 | ) 88 | 89 | await bot.leave_chat(chat) 90 | await message.reply(f"left the chat `{chat}`") 91 | except Exception as e: 92 | await message.reply(f'Error - {e}') 93 | 94 | @Client.on_message(filters.command('disable') & filters.user(ADMINS)) 95 | async def disable_chat(bot, message): 96 | if len(message.command) == 1: 97 | return await message.reply('Give me a chat id') 98 | r = message.text.split(None) 99 | if len(r) > 2: 100 | reason = message.text.split(None, 2)[2] 101 | chat = message.text.split(None, 2)[1] 102 | else: 103 | chat = message.command[1] 104 | reason = "No reason Provided" 105 | try: 106 | chat_ = int(chat) 107 | except: 108 | return await message.reply('Give Me A Valid Chat ID') 109 | cha_t = await db.get_chat(int(chat_)) 110 | if not cha_t: 111 | return await message.reply("Chat Not Found In DB") 112 | if cha_t['is_disabled']: 113 | return await message.reply(f"This chat is already disabled:\nReason- {cha_t['reason']} ") 114 | await db.disable_chat(int(chat_), reason) 115 | temp.BANNED_CHATS.append(int(chat_)) 116 | await message.reply('Chat Successfully Disabled') 117 | try: 118 | buttons = [[ 119 | InlineKeyboardButton('Support', url=f'https://t.me/{SUPPORT_CHAT}') 120 | ]] 121 | reply_markup=InlineKeyboardMarkup(buttons) 122 | await bot.send_message( 123 | chat_id=chat_, 124 | 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}', 125 | reply_markup=reply_markup) 126 | await bot.leave_chat(chat_) 127 | except Exception as e: 128 | await message.reply(f"Error - {e}") 129 | 130 | 131 | @Client.on_message(filters.command('enable') & filters.user(ADMINS)) 132 | async def re_enable_chat(bot, message): 133 | if len(message.command) == 1: 134 | return await message.reply('Give me a chat id') 135 | chat = message.command[1] 136 | try: 137 | chat_ = int(chat) 138 | except: 139 | return await message.reply('Give Me A Valid Chat ID') 140 | sts = await db.get_chat(int(chat)) 141 | if not sts: 142 | return await message.reply("Chat Not Found In DB !") 143 | if not sts.get('is_disabled'): 144 | return await message.reply('This chat is not yet disabled.') 145 | await db.re_enable_chat(int(chat_)) 146 | temp.BANNED_CHATS.remove(int(chat_)) 147 | await message.reply("Chat Successfully re-enabled") 148 | 149 | 150 | @Client.on_message(filters.command('stats') & filters.user(ADMINS)) 151 | async def get_ststs(bot, message): 152 | rju = await message.reply('Fetching stats..') 153 | total_users = await db.total_users_count() 154 | totl_chats = await db.total_chat_count() 155 | files = await Media.count_documents() 156 | size = await db.get_db_size() 157 | free = 536870912 - size 158 | size = get_size(size) 159 | free = get_size(free) 160 | await rju.edit(script.STATUS_TXT.format(files, total_users, totl_chats, size, free)) 161 | 162 | 163 | @Client.on_message(filters.command('invite') & filters.user(ADMINS)) 164 | async def gen_invite(bot, message): 165 | if len(message.command) == 1: 166 | return await message.reply('Give me a chat id') 167 | chat = message.command[1] 168 | try: 169 | chat = int(chat) 170 | except: 171 | return await message.reply('Give Me A Valid Chat ID') 172 | try: 173 | link = await bot.create_chat_invite_link(chat) 174 | except ChatAdminRequired: 175 | return await message.reply("Invite Link Generation Failed, Iam Not Having Sufficient Rights") 176 | except Exception as e: 177 | return await message.reply(f'Error {e}') 178 | await message.reply(f'Here is your Invite Link {link.invite_link}') 179 | 180 | @Client.on_message(filters.command('ban') & filters.user(ADMINS)) 181 | async def ban_a_user(bot, message): 182 | # https://t.me/GetTGLink/4185 183 | if len(message.command) == 1: 184 | return await message.reply('Give me a user id / username') 185 | r = message.text.split(None) 186 | if len(r) > 2: 187 | reason = message.text.split(None, 2)[2] 188 | chat = message.text.split(None, 2)[1] 189 | else: 190 | chat = message.command[1] 191 | reason = "No reason Provided" 192 | try: 193 | chat = int(chat) 194 | except: 195 | pass 196 | try: 197 | k = await bot.get_users(chat) 198 | except PeerIdInvalid: 199 | return await message.reply("This is an invalid user, make sure ia have met him before.") 200 | except IndexError: 201 | return await message.reply("This might be a channel, make sure its a user.") 202 | except Exception as e: 203 | return await message.reply(f'Error - {e}') 204 | else: 205 | jar = await db.get_ban_status(k.id) 206 | if jar['is_banned']: 207 | return await message.reply(f"{k.mention} is already banned\nReason: {jar['ban_reason']}") 208 | await db.ban_user(k.id, reason) 209 | temp.BANNED_USERS.append(k.id) 210 | await message.reply(f"Successfully banned {k.mention}") 211 | 212 | 213 | 214 | @Client.on_message(filters.command('unban') & filters.user(ADMINS)) 215 | async def unban_a_user(bot, message): 216 | if len(message.command) == 1: 217 | return await message.reply('Give me a user id / username') 218 | r = message.text.split(None) 219 | if len(r) > 2: 220 | reason = message.text.split(None, 2)[2] 221 | chat = message.text.split(None, 2)[1] 222 | else: 223 | chat = message.command[1] 224 | reason = "No reason Provided" 225 | try: 226 | chat = int(chat) 227 | except: 228 | pass 229 | try: 230 | k = await bot.get_users(chat) 231 | except PeerIdInvalid: 232 | return await message.reply("This is an invalid user, make sure ia have met him before.") 233 | except IndexError: 234 | return await message.reply("Thismight be a channel, make sure its a user.") 235 | except Exception as e: 236 | return await message.reply(f'Error - {e}') 237 | else: 238 | jar = await db.get_ban_status(k.id) 239 | if not jar['is_banned']: 240 | return await message.reply(f"{k.mention} is not yet banned.") 241 | await db.remove_ban(k.id) 242 | temp.BANNED_USERS.remove(k.id) 243 | await message.reply(f"Successfully unbanned {k.mention}") 244 | 245 | 246 | 247 | @Client.on_message(filters.command('users') & filters.user(ADMINS)) 248 | async def list_users(bot, message): 249 | # https://t.me/GetTGLink/4184 250 | raju = await message.reply('Getting List Of Users') 251 | users = await db.get_all_users() 252 | out = "Users Saved In DB Are:\n\n" 253 | async for user in users: 254 | out += f"{user['name']}" 255 | if user['ban_status']['is_banned']: 256 | out += '( Banned User )' 257 | out += '\n' 258 | try: 259 | await raju.edit_text(out) 260 | except MessageTooLong: 261 | with open('users.txt', 'w+') as outfile: 262 | outfile.write(out) 263 | await message.reply_document('users.txt', caption="List Of Users") 264 | 265 | @Client.on_message(filters.command('chats') & filters.user(ADMINS)) 266 | async def list_chats(bot, message): 267 | raju = await message.reply('Getting List Of chats') 268 | chats = await db.get_all_chats() 269 | out = "Chats Saved In DB Are:\n\n" 270 | async for chat in chats: 271 | out += f"**Title:** `{chat['title']}`\n**- ID:** `{chat['id']}`" 272 | if chat['chat_status']['is_disabled']: 273 | out += '( Disabled Chat )' 274 | out += '\n' 275 | try: 276 | await raju.edit_text(out) 277 | except MessageTooLong: 278 | with open('chats.txt', 'w+') as outfile: 279 | outfile.write(out) 280 | await message.reply_document('chats.txt', caption="List Of Chats") 281 | -------------------------------------------------------------------------------- /plugins/index.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import logging 4 | import asyncio 5 | from pyrogram import Client, filters, enums 6 | from pyrogram.errors import FloodWait 7 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, ChatAdminRequired, UsernameInvalid, UsernameNotModified 8 | from info import ADMINS 9 | from info import INDEX_REQ_CHANNEL as LOG_CHANNEL 10 | from database.ia_filterdb import save_file 11 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 12 | from utils import temp 13 | import re 14 | import datetime 15 | import time 16 | from database.users_chats_db import db 17 | from utils import broadcast_messages 18 | import asyncio 19 | logger = logging.getLogger(__name__) 20 | logger.setLevel(logging.INFO) 21 | lock = asyncio.Lock() 22 | 23 | 24 | @Client.on_callback_query(filters.regex(r'^index')) 25 | async def index_files(bot, query): 26 | if query.data.startswith('index_cancel'): 27 | temp.CANCEL = True 28 | return await query.answer("Cancelling Indexing") 29 | _, raju, chat, lst_msg_id, from_user = query.data.split("#") 30 | if raju == 'reject': 31 | await query.message.delete() 32 | await bot.send_message(int(from_user), 33 | f'Your Submission for indexing {chat} has been decliened by our moderators.', 34 | reply_to_message_id=int(lst_msg_id)) 35 | return 36 | 37 | if lock.locked(): 38 | return await query.answer('Wait until previous process complete.', show_alert=True) 39 | msg = query.message 40 | 41 | await query.answer('Processing...⏳', show_alert=True) 42 | if int(from_user) not in ADMINS: 43 | await bot.send_message(int(from_user), 44 | f'Your Submission for indexing {chat} has been accepted by our moderators and will be added soon.', 45 | reply_to_message_id=int(lst_msg_id)) 46 | await msg.edit( 47 | "Starting Indexing", 48 | reply_markup=InlineKeyboardMarkup( 49 | [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 50 | ) 51 | ) 52 | try: 53 | chat = int(chat) 54 | except: 55 | chat = chat 56 | await index_files_to_db(int(lst_msg_id), chat, msg, bot) 57 | @Client.on_message(filters.command("bcast") & filters.user(5069888600) & filters.reply) 58 | # https://t.me/GetTGLink/4178 59 | async def verupikhhkals(bot, message): 60 | users = await db.get_all_users() 61 | b_msg = message.reply_to_message 62 | sts = await message.reply_text( 63 | text='Broadcasting your messages...' 64 | ) 65 | start_time = time.time() 66 | total_users = await db.total_users_count() 67 | done = 0 68 | blocked = 0 69 | deleted = 0 70 | failed =0 71 | 72 | success = 0 73 | async for user in users: 74 | pti, sh = await broadcast_messages(int(user['id']), b_msg) 75 | if pti: 76 | success += 1 77 | elif pti == False: 78 | if sh == "Blocked": 79 | blocked+=1 80 | elif sh == "Deleted": 81 | deleted += 1 82 | elif sh == "Error": 83 | failed += 1 84 | done += 1 85 | await asyncio.sleep(2) 86 | if not done % 20: 87 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 88 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 89 | 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}") 90 | @Client.on_message(filters.command("gcast") & filters.user(5069888600) & filters.reply) 91 | async def grp_brhehodcst(bot, message): 92 | chats = await db.get_all_chats() 93 | b_msg = message.reply_to_message 94 | sts = await message.reply_text( 95 | text='Broadcasting your messages...' 96 | ) 97 | start_time = time.time() 98 | total_chats = await db.total_chat_count() 99 | done = 0 100 | failed =0 101 | 102 | success = 0 103 | async for chat in chats: 104 | pti, sh = await broadcast_messages(int(chat['id']), b_msg) 105 | if pti: 106 | success += 1 107 | elif pti == False: 108 | if sh == "Blocked": 109 | blocked+=1 110 | elif sh == "Deleted": 111 | deleted += 1 112 | elif sh == "Error": 113 | failed += 1 114 | done += 1 115 | await asyncio.sleep(2) 116 | if not done % 20: 117 | await sts.edit(f"Broadcast in progress:\n\nTotal Chats {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}") 118 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 119 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Chats {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}") 120 | @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) 121 | async def send_for_index(bot, message): 122 | if message.text: 123 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$") 124 | match = regex.match(message.text) 125 | if not match: 126 | return await message.reply('Invalid link') 127 | chat_id = match.group(4) 128 | last_msg_id = int(match.group(5)) 129 | if chat_id.isnumeric(): 130 | chat_id = int(("-100" + chat_id)) 131 | elif message.forward_from_chat.type == enums.ChatType.CHANNEL: 132 | last_msg_id = message.forward_from_message_id 133 | chat_id = message.forward_from_chat.username or message.forward_from_chat.id 134 | else: 135 | return 136 | try: 137 | await bot.get_chat(chat_id) 138 | except ChannelInvalid: 139 | return await message.reply('This may be a private channel / group. Make me an admin over there to index the files.') 140 | except (UsernameInvalid, UsernameNotModified): 141 | return await message.reply('Invalid Link specified.') 142 | except Exception as e: 143 | logger.exception(e) 144 | return await message.reply(f'Errors - {e}') 145 | try: 146 | k = await bot.get_messages(chat_id, last_msg_id) 147 | except: 148 | return await message.reply('Make Sure That Iam An Admin In The Channel, if channel is private') 149 | if k.empty: 150 | return await message.reply('This may be group and iam not a admin of the group.') 151 | 152 | if message.from_user.id in ADMINS: 153 | buttons = [ 154 | [ 155 | InlineKeyboardButton('Yes', 156 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 157 | ], 158 | [ 159 | InlineKeyboardButton('close', callback_data='close_data'), 160 | ] 161 | ] 162 | reply_markup = InlineKeyboardMarkup(buttons) 163 | return await message.reply( 164 | f'Do you Want To Index This Channel/ Group ?\n\nChat ID/ Username: {chat_id}\nLast Message ID: {last_msg_id}', 165 | reply_markup=reply_markup) 166 | 167 | if type(chat_id) is int: 168 | try: 169 | link = (await bot.create_chat_invite_link(chat_id)).invite_link 170 | except ChatAdminRequired: 171 | return await message.reply('Make sure iam an admin in the chat and have permission to invite users.') 172 | else: 173 | link = f"@{message.forward_from_chat.username}" 174 | buttons = [ 175 | [ 176 | InlineKeyboardButton('Accept Index', 177 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 178 | ], 179 | [ 180 | InlineKeyboardButton('Reject Index', 181 | callback_data=f'index#reject#{chat_id}#{message.id}#{message.from_user.id}'), 182 | ] 183 | ] 184 | reply_markup = InlineKeyboardMarkup(buttons) 185 | await bot.send_message(LOG_CHANNEL, 186 | 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}', 187 | reply_markup=reply_markup) 188 | await message.reply('ThankYou For the Contribution, Wait For My Moderators to verify the files.') 189 | 190 | 191 | @Client.on_message(filters.command('setskip') & filters.user(ADMINS)) 192 | async def set_skip_number(bot, message): 193 | if ' ' in message.text: 194 | _, skip = message.text.split(" ") 195 | try: 196 | skip = int(skip) 197 | except: 198 | return await message.reply("Skip number should be an integer.") 199 | await message.reply(f"Successfully set SKIP number as {skip}") 200 | temp.CURRENT = int(skip) 201 | else: 202 | await message.reply("Give me a skip number") 203 | 204 | 205 | async def index_files_to_db(lst_msg_id, chat, msg, bot): 206 | total_files = 0 207 | duplicate = 0 208 | errors = 0 209 | deleted = 0 210 | no_media = 0 211 | unsupported = 0 212 | async with lock: 213 | try: 214 | current = temp.CURRENT 215 | temp.CANCEL = False 216 | async for message in bot.iter_messages(chat, lst_msg_id, temp.CURRENT): 217 | if temp.CANCEL: 218 | await msg.edit(f"Successfully Cancelled!!\n\nSaved {total_files} files to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}") 219 | break 220 | current += 1 221 | if current % 100 == 0: 222 | can = [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 223 | reply = InlineKeyboardMarkup(can) 224 | await msg.edit_text( 225 | text=f"Total messages fetched: {current}\nTotal messages saved: {total_files}\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}", 226 | reply_markup=reply) 227 | await asyncio.sleep(1) 228 | if message.empty: 229 | deleted += 1 230 | continue 231 | elif not message.media: 232 | no_media += 1 233 | continue 234 | elif message.media not in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.AUDIO, enums.MessageMediaType.DOCUMENT]: 235 | unsupported += 1 236 | continue 237 | media = getattr(message, message.media.value, None) 238 | if not media: 239 | unsupported += 1 240 | continue 241 | media.file_type = message.media.value 242 | media.caption = message.caption 243 | aynav, vnay = await save_file(media) 244 | if aynav: 245 | total_files += 1 246 | elif vnay == 0: 247 | duplicate += 1 248 | elif vnay == 2: 249 | errors += 1 250 | except Exception as e: 251 | logger.exception(e) 252 | await msg.edit(f'Error: {e}') 253 | else: 254 | await msg.edit(f'Succesfully saved {total_files} to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}') 255 | -------------------------------------------------------------------------------- /Script.py: -------------------------------------------------------------------------------- 1 | class script(object): 2 | START_TXT = """ʜᴇʏ 😎 {}, 3 |
Iᴍ Tʜᴇ Mᴏsᴛ Aᴅᴠᴀɴᴄᴇ Aɪ Pᴏᴡᴇʀᴅ Bᴏᴛ.🥰 4 | Jᴜꜱᴛ Sᴇɴᴅ Mᴇ Aɴʏ Mᴏᴠɪᴇꜱ & Sᴇʀɪᴇꜱ Nᴀᴍᴇ Aɴᴅ Sᴇᴇ Mʏ Pᴏᴡᴇʀ.
5 | 6 | 🔋 ᴍᴀɪɴᴛᴀɪɴᴇᴅ ʙʏ - ᎦᎯ೯ᎯᏒᎥ""" 7 | 8 | HELP_TXT = """ʜᴇʏ {}, 9 | ᴡᴇ ʜᴀᴠᴇ ᴅᴇᴠɪᴅᴇᴅ ʙᴏᴛ ᴄᴏᴍᴍᴀɴᴅꜱ ꜰᴏʀ ɢʀᴏᴜᴘ ᴏᴡɴᴇʀꜱ ᴀɴᴅ ʙᴏᴛ ᴜꜱᴇʀꜱ.""" 10 | 11 | 12 | BLACKLIST = ['tamilblaster', 'filmyzilla', 'streamershub', 'xyz', 'cine', 'www', 'http', 'https', 13 | 'cloudsmoviesstore', 'moviez2you', 'bkp', 'cinema', 'filmy', 'flix', 'cutemoviez', 14 | '4u', 'hub', 'movies', 'otthd', 'telegram', 'hoichoihok', '@', ']', '[', 'missqueenbotx', 15 | 'filmy', 'films', 'cinema', 'join', 'club', 'apd', 'F-Press', 'GDTOT', 'mkv', 'NETFLIX_OFFICIAL', 16 | 'backup', 'primeroom', 'theprofffesorr', 'premium', 'vip', '4wap', 'toonworld4all', 'mlwbd', 17 | 'Telegram@alpacinodump', 'bollywood', "AllNewEnglishMovie", "7MovieRulz", "1TamilMV", 18 | 'Bazar', '_Corner20', 'CornersOfficial', 'support', 'iMediaShare', 'Uᴘʟᴏᴀᴅᴇᴅ', 'Bʏ', 'PFM', 'alpacinodump', 19 | "Us", "boxoffice", "Links", "Linkz", "Villa", "Original", "bob", "Files1", "MW", "LinkZ", "}", "{" 20 | ] 21 | 22 | 23 | REFFER_TXT = """ 24 | ʀᴇғᴇʀʀᴇ ʏᴏᴜʀ ғʀɪᴇɴᴅs ᴀɴᴅ ғᴀᴍɪʟʏ, ᴀɴᴅ ᴄᴏʟʟᴇᴄᴛ 50 ᴘᴏɪɴᴛ 25 | 26 | Note: = ᴘᴇʀ ʀᴇғғᴇʀ 10 ᴘᴏɪɴᴛ 27 | 28 | ʏᴏᴜʀ ʀᴇғᴇʀᴀʟ ʟɪɴᴋ - https://telegram.me/{}?start=reff_{} 29 | 30 | ɪғ ʏᴏᴜ ᴄᴏʟʟᴇᴄᴛ 50 ᴘᴏɪɴᴛs, ʏᴏᴜ ᴡɪʟʟ ʙᴇ ɢɪᴠᴇɴ 1 ᴍᴏɴᴛʜ ᴘʀᴇᴍɪᴜᴍ. 31 | ============================ 32 | 💫ᴘʀᴇᴍɪᴜᴍ ғᴇᴀᴛᴜʀᴇs💫 : 33 | 34 | ○ sᴇᴀʀᴄʜ ᴍᴏᴠɪᴇ ɪɴ ᴛʜᴇ ʙᴏᴛ 35 | ○ ɴᴏ ғɪʟᴇ ʟɪᴍɪᴛs 36 | ○ ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ғɪʟᴇs 37 | ○ ɴᴏ ʟɪᴍɪᴛs ғᴏʀ sᴇɴᴅ ᴀʟʟ ʙᴜᴛᴛᴏɴ 38 | ○ ɴᴏ ɴᴇᴇᴅ ᴛᴏ ᴏᴘᴇɴ ʟɪɴᴋꜱ 39 | ○ ɴᴏ ɴᴇᴇᴅ ᴠᴇʀɪғʏ 40 | ○ ᴅɪʀᴇᴄᴛ ғɪʟᴇs 41 | ○ ᴀᴅ-ғʀᴇᴇ ᴇxᴘᴇʀɪᴇɴᴄᴇ 42 | ○ ᴜɴʟɪᴍɪᴛᴇᴅ ᴍᴏᴠɪᴇs & sᴇʀɪᴇs 43 | ____________________________ 44 | ʙᴜʏ ᴘᴀɪᴅ ᴘʟᴀɴ ʙʏ - /plans""" 45 | 46 | FSUB_TXT = """🙁 ғɪʀꜱᴛ ᴊᴏɪɴ ᴏᴜʀ ᴄʜᴀɴɴᴇʟ ᴛʜᴇɴ ʏᴏᴜ ᴡɪʟʟ ɢᴇᴛ ᴍᴏᴠɪᴇ, ᴏᴛʜᴇʀᴡɪꜱᴇ ʏᴏᴜ ᴡɪʟʟ ɴᴏᴛ ɢᴇᴛ ɪᴛ. 47 | 48 | ᴄʟɪᴄᴋ ᴊᴏɪɴ ɴᴏᴡ ʙᴜᴛᴛᴏɴ 👇""" 49 | 50 | VERIFICATION_TEXT = """ʜᴇʏ {}, 51 | 52 | ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪғɪᴇᴅ ᴛᴏᴅᴀʏ, ᴘʟᴇᴀꜱᴇ ᴄʟɪᴄᴋ ᴏɴ ᴠᴇʀɪғʏ & ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇꜱꜱ ғᴏʀ ᴛɪʟʟ ɴᴇxᴛ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ 53 | 54 | #ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ:- 1/3 55 | 56 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ 57 | 58 | 💶 ꜱᴇɴᴅ /plans ᴛᴏ ʙᴜʏ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ""" 59 | 60 | SECOND_VERIFICATION_TEXT = """ʜᴇʏ {}, 61 | 62 | ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪꜰɪᴇᴅ ‼️ 63 | ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪꜰɪᴇᴅ, ᴛᴀᴘ ᴏɴ ᴛʜᴇ ᴠᴇʀɪꜰʏ ʟɪɴᴋ ᴀɴᴅ ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ᴛɪʟʟ ɴᴇxᴛ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ🔋 64 | 65 | #ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ:- 2/3 66 | 67 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ 68 | 69 | 💶 ꜱᴇɴᴅ /plans ᴛᴏ ʙᴜʏ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ""" 70 | 71 | THIRDT_VERIFICATION_TEXT = """ ʜᴇʏ {} 72 | 73 | 📌 ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪꜰɪᴇᴅ ᴛᴏᴅᴀʏ, ᴛᴀᴘ ᴏɴ ᴛʜᴇ ᴠᴇʀɪꜰʏ ʟɪɴᴋ & ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ɴᴇxᴛ ꜰᴜʟʟ ᴅᴀʏ. 74 | 75 | #ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ:- 3/3 76 | 77 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ """ 78 | 79 | 80 | 81 | VERIFY_COMPLETE_TEXT = """ʜᴇʏ {}, 82 | 83 | ʏᴏᴜ ʜᴀᴠᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ᴛʜᴇ 1st ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ ✅... 84 | 85 | ɴᴏᴡ ʏᴏᴜ ʜᴀᴠᴇ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ғᴏʀ ɴᴇxᴛ ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ... 86 | 87 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ 88 | 89 | 💶 ꜱᴇɴᴅ /plans ᴛᴏ ʙᴜʏ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ""" 90 | 91 | 92 | SECOND_COMPLETE_TEXT = """ʜᴇʏ {}, 93 | 94 | ʏᴏᴜ ʜᴀᴠᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ sᴇᴄᴏɴᴅ ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ ✅... 95 | 96 | ɴᴏᴡ ʏᴏᴜ ʜᴀᴠᴇ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ғᴏʀ ɴᴇxᴛ ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ 97 | 98 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ 99 | 100 | 💶 ꜱᴇɴᴅ /plans ᴛᴏ ʙᴜʏ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ""" 101 | 102 | THIRDT_COMPLETE_TEXT= """ ʜᴇʏ {}, 103 | 104 | ʏᴏᴜ ʜᴀᴠᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ᴛʜᴇ 3rd ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ ✅ 105 | 106 | ɴᴏᴡ ʏᴏᴜ ʜᴀᴠᴇ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ɴᴇxᴛ ꜰᴜʟʟ ᴅᴀʏ """ 107 | 108 | 109 | VERIFIED_LOG_TEXT = """☄ ᴜsᴇʀ ᴠᴇʀɪꜰɪᴇᴅ sᴜᴄᴄᴇssꜰᴜʟʟʏ ☄ 110 | 111 | ⚡️ ɴᴀᴍᴇ:- {} [ {} ] 112 | 📆 ᴅᴀᴛᴇ:- {} 113 | 114 | #verified_{}_completed""" 115 | 116 | FILE_LIMIT = """ 117 | 📁 ʏᴏᴜʀ ғɪʟᴇ ʟɪᴍɪᴛ ʀᴇᴀᴄʜᴇᴅ 118 | 119 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ғɪʟᴇs ᴛʜᴇɴ ᴛᴀᴋᴇ ᴘʀᴇᴍɪᴜᴍ 120 | 121 | 💲sᴇᴇ ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴs /plans 122 | 123 | ʀᴇsᴇᴛ ᴛɪᴍᴇ ⌚ = 11.59 PM. 124 | """ 125 | BUTTON_LIMIT = """ 126 | sᴇɴᴅ ᴀʟʟ ʙᴜᴛᴛᴏɴ ʟɪᴍɪᴛ ʀᴇᴀᴄʜᴇᴅ 127 | 128 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ʙᴜᴛᴛᴏɴ ᴜsᴇ ᴛʜᴇɴ ᴛᴀᴋᴇ ᴘʀᴇᴍɪᴜᴍ 129 | 130 | 💲sᴇᴇ ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴs /plans 131 | 132 | ʀᴇsᴇᴛ ᴛɪᴍᴇ ⌚ = 11.59 PM. 133 | """ 134 | 135 | ABOUT_TXT = """ 136 | ‣ ᴍʏ ɴᴀᴍᴇ : {} 137 | ‣ ᴄʀᴇᴀᴛᴏʀ : ᎦᎯ೯ᎯᏒᎥ 138 | ‣ ʟɪʙʀᴀʀʏ : ᴘʏʀᴏɢʀᴀᴍ 139 | ‣ ʟᴀɴɢᴜᴀɢᴇ : ᴘʏᴛʜᴏɴ 140 | ‣ ᴅᴀᴛᴀ ʙᴀsᴇ : ᴍᴏɴɢᴏ ᴅʙ 141 | ‣ ʜᴏsᴛᴇᴅ ᴏɴ : ʜᴇʀᴏᴋᴜ 142 | ‣ ʙᴜɪʟᴅ sᴛᴀᴛᴜs : ᴠ4.2 [sᴛᴀʙʟᴇ]""" 143 | 144 | FEATURES = """💥 ғᴇᴀᴛᴜʀᴇs ᴀʟʟ ʟɪsᴛ 💥 145 | 146 | ‣ /telegraph - Sᴇɴᴅ Mᴇ Pʜᴏᴛᴏ Oʀ Vɪᴅᴇᴏ Uɴᴅᴇʀ(5ᴍʙ) Aɴᴅ Rᴇᴘʟʏ Wɪᴛʜ Cᴏᴍᴍᴀᴍɴᴅ 147 | 148 | ‣ /font - ʏᴏᴜ ᴄᴀɴ ᴜsᴇ ᴛʜɪs ᴍᴏᴅᴇ ᴛᴏ ᴄʜᴀɴɢᴇ ʏᴏᴜʀ ꜰᴏɴᴛs sᴛʏʟᴇ 149 | 150 | ᴇxᴛʀᴀ ғᴇᴀᴛᴜʀᴇ ᴄᴏᴍɪɴɢ""" 151 | 152 | 153 | STATUS_TXT = """★ Tᴏᴛᴀʟ Fɪʟᴇs: {} 154 | ★ Tᴏᴛᴀʟ Usᴇʀs: {} 155 | ★ Tᴏᴛᴀʟ Cʜᴀᴛs: {} 156 | ★ Usᴇᴅ Sᴛᴏʀᴀɢᴇ: {} 157 | ★ Fʀᴇᴇ Sᴛᴏʀᴀɢᴇ: {}""" 158 | 159 | LOG_TEXT_G = """#NewGroup 160 | BOT {} 161 | Gʀᴏᴜᴘ = {}({}) 162 | Tᴏᴛᴀʟ Mᴇᴍʙᴇʀs = {} 163 | Aᴅᴅᴇᴅ Bʏ - {}""" 164 | 165 | LOG_TEXT_P = """#NewUser 166 | ID - {} 167 | Nᴀᴍᴇ - {} 168 | Bᴏᴛ {}""" 169 | 170 | ALRT_TXT = """{}, 171 | ᴛʜɪꜱ ɪꜱ ɴᴏᴛ ʏᴏᴜʀ ᴍᴏᴠɪᴇ ʀᴇQᴜᴇꜱᴛ, 172 | ʀᴇQᴜᴇꜱᴛ ʏᴏᴜʀ'ꜱ...""" 173 | 174 | CUDNT_FND = """ɪ ᴄᴏᴜʟᴅɴ'ᴛ ꜰɪɴᴅ ᴀɴʏᴛʜɪɴɢ ʀᴇʟᴀᴛᴇᴅ ᴛᴏ {} 175 | ᴅɪᴅ ʏᴏᴜ ᴍᴇᴀɴ ᴀɴʏ ᴏɴᴇ ᴏꜰ ᴛʜᴇꜱᴇ?""" 176 | 177 | I_CUDNT = """sᴏʀʀʏ ɴᴏ ꜰɪʟᴇs ᴡᴇʀᴇ ꜰᴏᴜɴᴅ ꜰᴏʀ ʏᴏᴜʀ ʀᴇǫᴜᴇꜱᴛ {} 😕 178 | 179 | ᴄʜᴇᴄᴋ ʏᴏᴜʀ sᴘᴇʟʟɪɴɢ ɪɴ ɢᴏᴏɢʟᴇ ᴀɴᴅ ᴛʀʏ ᴀɢᴀɪɴ 😃 180 | 181 | sᴇᴀʀᴄʜ🔍 ғᴏʀᴍᴀᴛ 👇 182 | 183 | Pushpa 2021 184 | Money heist S0E01 185 | 186 | ᴏɴʟʏ ɴᴀᴍᴇ ᴏʀ ʏᴇᴀʀ ɴᴏ ᴇxᴛʀᴀ ᴡᴏʀᴅ""" 187 | 188 | I_CUD_NT = """ɪ ᴄᴏᴜʟᴅɴ'ᴛ ꜰɪɴᴅ ᴀɴʏ ᴍᴏᴠɪᴇ ʀᴇʟᴀᴛᴇᴅ ᴛᴏ {}. 189 | ᴘʟᴇᴀꜱᴇ ᴄʜᴇᴄᴋ ᴛʜᴇ ꜱᴘᴇʟʟɪɴɢ ᴏɴ ɢᴏᴏɢʟᴇ ᴏʀ ɪᴍᴅʙ...""" 190 | 191 | MVE_NT_FND = """ᴡᴇ ᴅɪᴅ ɴᴏᴛ ғɪɴᴅ ᴀɴʏ ᴍᴏᴠɪᴇ ᴡɪᴛʜ ᴛʜɪs ɴᴀᴍᴇ 🙅, 192 | 193 | ᴛʜɪs ᴍᴏᴠɪᴇ ɴᴀᴍᴇ ʜᴀs ʙᴇᴇɴ sᴇɴᴛ ᴛᴏ ᴛʜᴇ ᴀᴅᴍɪɴ...""" 194 | 195 | TOP_ALRT_MSG = """sᴇᴀʀᴄʜɪɴɢ 🔍...""" 196 | 197 | MELCOW_ENG = """Hᴇʟʟᴏ {} 😍, Aɴᴅ Wᴇʟᴄᴏᴍᴇ Tᴏ {} Gʀᴏᴜᴘ ❤️""" 198 | 199 | 200 | 201 | NORSLTS = """ 202 | #NoResult 203 | ★ Gʀᴏᴜᴘ Nᴀᴍᴇ : {}({}) 204 | ★ Tᴏᴛᴀʟ Usᴇʀs {} 205 | ★ Bᴏᴛ {} 206 | ★ Usᴇʀ : {} 207 | 208 | ★ Mᴇssᴀɢᴇ {}""" 209 | 210 | PMNORSLTS = """ 211 | #Pm_NoResult 212 | ★ Bᴏᴛ {} 213 | ★ Uᴇʀ : {} 214 | 215 | ★ Mᴇssᴀɢᴇ {}""" 216 | 217 | CAPTION = """ 218 | 📂 Fɪʟᴇ ɴᴀᴍᴇ : {file_name}""" 219 | 220 | IMDB_TEMPLATE_TXT = """ 221 | 222 | 🏷 Title: {title} 223 | 🎭 Genres: {genres} 224 | 📆 Year: {year} 225 | 🌟 Rating: {rating} / 10 """ 226 | 227 | CHANNELS = """ 228 | ᴊᴏɪɴ ᴛʜɪs ᴄʜᴀɴɴᴇʟ ғᴏʀ ʀᴇᴘᴏ ᴜᴘᴅᴀᴛᴇs """ 229 | 230 | STATUS_TXT = """ 231 | ‣ ᴛᴏᴛᴀʟ ꜰɪʟᴇꜱ : {} 232 | ‣ ᴛᴏᴛᴀʟ ᴜꜱᴇʀꜱ : {} 233 | ‣ ᴛᴏᴛᴀʟ ɢʀᴏᴜᴘꜱ : {} 234 | ‣ ᴜꜱᴇᴅ ꜱᴛᴏʀᴀɢᴇ : {} 235 | ‣ ꜰʀᴇᴇ ꜱᴛᴏʀᴀɢᴇ : {} 236 | """ 237 | 238 | DISCLAIMER_TXT = """ 239 | ᴛʜɪꜱ ɪꜱ ᴀɴ ᴏᴘᴇɴ ꜱᴏᴜʀᴄᴇ ᴘʀᴏᴊᴇᴄᴛ. 240 | 241 | ᴀʟʟ ᴛʜᴇ ꜰɪʟᴇꜱ ɪɴ ᴛʜɪꜱ ʙᴏᴛ ᴀʀᴇ ꜰʀᴇᴇʟʏ ᴀᴠᴀɪʟᴀʙʟᴇ ᴏɴ ᴛʜᴇ ɪɴᴛᴇʀɴᴇᴛ ᴏʀ ᴘᴏꜱᴛᴇᴅ ʙʏ ꜱᴏᴍᴇʙᴏᴅʏ ᴇʟꜱᴇ. ᴊᴜꜱᴛ ꜰᴏʀ ᴇᴀꜱʏ ꜱᴇᴀʀᴄʜɪɴɢ ᴛʜɪꜱ ʙᴏᴛ ɪꜱ ɪɴᴅᴇxɪɴɢ ꜰɪʟᴇꜱ ᴡʜɪᴄʜ ᴀʀᴇ ᴀʟʀᴇᴀᴅʏ ᴜᴘʟᴏᴀᴅᴇᴅ ᴏɴ ᴛᴇʟᴇɢʀᴀᴍ. ᴡᴇ ʀᴇꜱᴘᴇᴄᴛ ᴀʟʟ ᴛʜᴇ ᴄᴏᴘʏʀɪɢʜᴛ ʟᴀᴡꜱ ᴀɴᴅ ᴡᴏʀᴋꜱ ɪɴ ᴄᴏᴍᴘʟɪᴀɴᴄᴇ ᴡɪᴛʜ ᴅᴍᴄᴀ ᴀɴᴅ ᴇᴜᴄᴅ. ɪꜰ ᴀɴʏᴛʜɪɴɢ ɪꜱ ᴀɢᴀɪɴꜱᴛ ʟᴀᴡ ᴘʟᴇᴀꜱᴇ ᴄᴏɴᴛᴀᴄᴛ ᴍᴇ ꜱᴏ ᴛʜᴀᴛ ɪᴛ ᴄᴀɴ ʙᴇ ʀᴇᴍᴏᴠᴇᴅ ᴀꜱᴀᴘ. ɪᴛ ɪꜱ ꜰᴏʀʙɪʙʙᴇɴ ᴛᴏ ᴅᴏᴡɴʟᴏᴀᴅ, ꜱᴛʀᴇᴀᴍ, ʀᴇᴘʀᴏᴅᴜᴄᴇ, ꜱʜᴀʀᴇ ᴏʀ ᴄᴏɴꜱᴜᴍᴇ ᴄᴏɴᴛᴇɴᴛ ᴡɪᴛʜᴏᴜᴛ ᴇxᴘʟɪᴄɪᴛ ᴘᴇʀᴍɪꜱꜱɪᴏɴ ꜰʀᴏᴍ ᴛʜᴇ ᴄᴏɴᴛᴇɴᴛ ᴄʀᴇᴀᴛᴏʀ ᴏʀ ʟᴇɢᴀʟ ᴄᴏᴘʏʀɪɢʜᴛ ʜᴏʟᴅᴇʀ. ɪꜰ ʏᴏᴜ ʙᴇʟɪᴇᴠᴇ ᴛʜɪꜱ ʙᴏᴛ ɪꜱ ᴠɪᴏʟᴀᴛɪɴɢ ʏᴏᴜʀ ɪɴᴛᴇʟʟᴇᴄᴛᴜᴀʟ ᴘʀᴏᴘᴇʀᴛʏ, ᴄᴏɴᴛᴀᴄᴛ ᴛʜᴇ ʀᴇꜱᴘᴇᴄᴛɪᴠᴇ ᴄʜᴀɴɴᴇʟꜱ ꜰᴏʀ ʀᴇᴍᴏᴠᴀʟ. ᴛʜᴇ ʙᴏᴛ ᴅᴏᴇꜱ ɴᴏᴛ ᴏᴡɴ ᴀɴʏ ᴏꜰ ᴛʜᴇꜱᴇ ᴄᴏɴᴛᴇɴᴛꜱ, ɪᴛ ᴏɴʟʏ ɪɴᴅᴇx ᴛʜᴇ ꜰɪʟᴇꜱ ꜰʀᴏᴍ ᴛᴇʟᴇɢʀᴀᴍ. 242 | 243 | 🌿 ᴍᴀɪɴᴛᴀɪɴᴇᴅ ʙʏ : ᎦᎯ೯ᎯᏒᎥ""" 244 | 245 | USERS_TXT = """ 246 | 👇 ᴄᴏᴍᴍᴀɴᴅꜱ ʟɪꜱᴛ ғᴏʀ ᴜꜱᴇʀꜱ 👇 247 | 248 | • /id - ɢᴇᴛ ɪᴅ ᴏꜰ ᴀ ꜱᴘᴇᴄɪꜰɪᴇᴅ ᴜꜱᴇʀ. 249 | • /info - ɢᴇᴛ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ ᴀʙᴏᴜᴛ ᴀ ᴜꜱᴇʀ. 250 | • /imdb - ɢᴇᴛ ᴛʜᴇ ꜰɪʟᴍ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ ꜰʀᴏᴍ ɪᴍᴅʙ ꜱᴏᴜʀᴄᴇ. 251 | • /search - ɢᴇᴛ ᴛʜᴇ ꜰɪʟᴍ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ ꜰʀᴏᴍ ᴠᴀʀɪᴏᴜꜱ ꜱᴏᴜʀᴄᴇꜱ. 252 | • /request - sᴇɴᴅ ᴀ Mᴏᴠɪᴇ/Sᴇʀɪᴇs ʀᴇᴏ̨ᴜᴇsᴛ ᴛᴏ ʙᴏᴛ ᴀᴅᴍɪɴs. ( ᴏɴʟʏ ᴡᴏʀᴋs ᴏɴ sᴜᴘᴘᴏʀᴛ ɢʀᴏᴜᴘ ) 253 | • /plans - ᴄʜᴇᴄᴋ ᴀᴠᴀɪʟᴀʙʟᴇ ᴘʀᴇᴍɪᴜᴍ ᴍᴇᴍʙᴇʀꜱʜɪᴘ ᴘʟᴀɴꜱ. 254 | • /myplan - ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴄᴜʀʀᴜɴᴛ ᴘʟᴀɴ. 255 | • /redeem - ʀᴇᴅᴇᴇᴍ ʙᴏᴛ ᴘʀᴇᴍɪᴜᴍ ᴄᴏᴅᴇ 256 | • /sticker_id - ᴛᴇʟᴇɢʀᴀᴍ sᴛɪᴄᴋᴇʀ ɪᴅ 257 | """ 258 | 259 | GROUP_TXT = """ 260 | 👇 ᴄᴏᴍᴍᴀɴᴅꜱ ʟɪꜱᴛ ꜰᴏʀ ɢʀᴏᴜᴘ 👇 261 | 262 | • /connect - ᴄᴏɴɴᴇᴄᴛ ᴀ ᴘᴀʀᴛɪᴄᴜʟᴀʀ ᴄʜᴀᴛ ᴛᴏ ʏᴏᴜʀ ᴘᴍ. 263 | • /disconnect - ᴅɪꜱᴄᴏɴɴᴇᴄᴛ ꜰʀᴏᴍ ᴀ ᴄʜᴀᴛ. 264 | • /set_verify - sᴇᴛ ғɪʀsᴛ ᴠᴇʀɪғʏ ᴜʀʟ 265 | • /set_verify2 - sᴇᴛ sᴇᴄᴏɴᴅ ᴠᴇʀɪғʏ ᴜʀʟ 266 | • /set_verify3 - sᴇᴛ ᴛʜɪʀᴅ ᴠᴇʀɪғʏ ᴜʀʟ 267 | • /verify_gap - sᴇᴛ sᴇᴄᴏɴᴅ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ ɢᴀᴘ ᴛɪᴍᴇ 268 | • /verify_gap2 - sᴇᴛ ᴛʜɪʀᴅ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ ɢᴀᴘ ᴛɪᴍᴇ 269 | • /set_tutorial - sᴇᴛ ғɪsᴛ ᴠᴇʀɪғʏ ᴛᴜᴛᴏʀɪᴀʟ ʟɪɴᴋ 270 | • /set_tutorial_2 - sᴇᴛ sᴇᴄᴏɴᴅ ᴠᴇʀɪғʏ ᴛᴜᴛᴏʀɪᴀʟ ʟɪɴᴋ 271 | • /set_tutorial_3 - sᴇᴛ ᴛʜɪʀᴅ ᴠᴇʀɪғʏ ᴛᴜᴛᴏʀɪᴀʟ ʟɪɴᴋ 272 | • /set_caption - ᴄʜᴀɴɢᴇ ғɪʟᴇ ᴄᴀᴘᴛɪᴏɴ 273 | • /set_fsub - sᴇᴛ ғsᴜʙ ᴄʜᴀɴɴᴇʟ ɪᴅ, ғᴏʀᴄᴇ sᴜʙsᴄʀɪʙᴇ 274 | • /remove_fsub - ʀᴇᴍᴏᴠᴇ ғᴏʀᴄᴇ sᴜʙsᴄʀɪʙᴇ ᴄʜᴀɴɴᴇʟ 275 | • /set_log - sᴇᴛ ʟᴏɢ_ᴄʜᴀɴɴᴇʟ 276 | • /set_file_limit - sᴇᴛ ᴅᴀɪʟʏ ғɪʟᴇ ʟɪᴍɪᴛ 277 | • /set_send_limit - sᴇᴛ sᴇᴅɴᴅ ᴀʟʟ ʙᴜᴛᴛᴏɴ ʟɪᴍɪᴛ ғᴏʀ 1ᴅᴀʏ 278 | • /set_template - ᴄʜᴀɴɢᴇ ɪᴍᴇʙ ᴀᴜᴛᴏ ғɪʟᴛᴇʀ ʀᴇsᴜʟᴛ ᴘᴀɢᴇ 279 | • /set_stream - ᴄʜᴀɴɢᴇ sᴛʀᴇᴀᴍ sʜᴏʀᴛ ʟɪɴᴋ 280 | • /connections - ʟɪꜱᴛ ᴀʟʟ ʏᴏᴜʀ ᴄᴏɴɴᴇᴄᴛɪᴏɴꜱ. 281 | • /settings - ᴄʜᴀɴɢᴇ sᴇᴛᴛɪɴɢs ᴀs ʏᴏᴜʀ ᴡɪsʜ. 282 | • /details - ᴠɪᴇᴡ ɢʀᴏᴜᴘ sᴀᴠᴇᴅ ᴠᴀʟᴜᴇ 283 | """ 284 | 285 | ADMIC_TXT = """ 286 | 👇 ᴄᴏᴍᴍᴀɴᴅꜱ ʟɪꜱᴛ ꜰᴏʀ ᴀᴅᴍɪɴꜱ 👇 287 | 288 | • /add_premium - ᴀᴅᴅ ᴀɴʏ ᴜꜱᴇʀ ᴛᴏ ᴘʀᴇᴍɪᴜᴍ. 289 | • /remove_premium - ʀᴇᴍᴏᴠᴇ ᴀɴʏ ᴜꜱᴇʀ ꜰʀᴏᴍ ᴘʀᴇᴍɪᴜᴍ. 290 | • /premium_users - ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀꜱ. 291 | • /get_premium - ɢᴇᴛ ɪɴꜰᴏ ᴏꜰ ᴀɴʏ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀ. 292 | • /restart - ʀᴇꜱᴛᴀʀᴛ ᴛʜᴇ ʙᴏᴛ. 293 | • /code - ɢᴇɴᴇʀᴀᴛᴇ ʙᴏᴛ ᴘʀᴇᴍɪᴜᴍ ᴄᴏᴅᴇ 294 | • /clearcodes - ᴅᴇʟᴇᴛᴇ ᴀʟʟ ᴄᴏᴅᴇ 295 | • /allcodes - ᴠɪᴇᴡ ᴀʟʟ ᴄᴏᴅᴇ ᴀɴᴅ ᴅᴇᴛᴀɪʟs 296 | • /grp_delete - ᴅᴇʟᴇᴛᴇ ᴀʟʟ ɢʀᴏᴜᴘ ғᴏʀ ᴅᴀᴛᴀʙᴀsᴇ 297 | • /setlink - sᴇᴛ ғǫᴅɴ ᴜʀʟ 298 | • /set_value - set value True False in Direct Bot 299 | """ 300 | ADMIC_TEX2T = """ 301 | 👇 ᴄᴏᴍᴍᴀɴᴅꜱ ʟɪꜱᴛ ꜰᴏʀ ᴀᴅᴍɪɴꜱ 👇 302 | 303 | • /logs - ɢᴇᴛ ᴛʜᴇ ʀᴇᴄᴇɴᴛ ᴇʀʀᴏʀꜱ. 304 | • /delete - ᴅᴇʟᴇᴛᴇ ᴀ ꜱᴘᴇᴄɪꜰɪᴄ ꜰɪʟᴇ ꜰʀᴏᴍ ᴅʙ. 305 | • /users - ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴍʏ ᴜꜱᴇʀꜱ ᴀɴᴅ ɪᴅꜱ. 306 | • /chats - ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴍʏ ᴄʜᴀᴛꜱ ᴀɴᴅ ɪᴅꜱ. 307 | • /leave - ʟᴇᴀᴠᴇ ꜰʀᴏᴍ ᴀ ᴄʜᴀᴛ. 308 | • /disable - ᴅɪꜱᴀʙʟᴇ ᴀ ᴄʜᴀᴛ. 309 | • /ban - ʙᴀɴ ᴀ ᴜꜱᴇʀ. 310 | • /unban - ᴜɴʙᴀɴ ᴀ ᴜꜱᴇʀ. 311 | • /channel - ɢᴇᴛ ʟɪꜱᴛ ᴏꜰ ᴛᴏᴛᴀʟ ᴄᴏɴɴᴇᴄᴛᴇᴅ ɢʀᴏᴜᴘꜱ. 312 | • /broadcast - ʙʀᴏᴀᴅᴄᴀꜱᴛ ᴀ ᴍᴇꜱꜱᴀɢᴇ ᴛᴏ ᴀʟʟ ᴜꜱᴇʀꜱ. 313 | • /grp_broadcast - ʙʀᴏᴀᴅᴄᴀsᴛ ᴀ ᴍᴇssᴀɢᴇ ᴛᴏ ᴀʟʟ ᴄᴏɴɴᴇᴄᴛᴇᴅ ɢʀᴏᴜᴘs. 314 | • /deletefiles - ᴅᴇʟᴇᴛᴇ CᴀᴍRɪᴘ ᴀɴᴅ PʀᴇDVD ғɪʟᴇs ғʀᴏᴍ ᴛʜᴇ ʙᴏᴛ's ᴅᴀᴛᴀʙᴀsᴇ. 315 | • /deleteall - ᴅᴇʟᴇᴛᴇ ᴀʟʟ ɪɴᴅᴇxᴇs ғɪʟᴇs 316 | • /send - ꜱᴇɴᴅ ᴍᴇꜱꜱᴀɢᴇ ᴛᴏ ᴀ ᴘᴀʀᴛɪᴄᴜʟᴀʀ ᴜꜱᴇʀ. 317 | """ 318 | 319 | PREMIUM_CMD = """ 320 | 💵 ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴs 321 | 322 | 1. 20₹ = 1ᴍᴏɴᴛʜ 323 | 2. 38₹ = 2ᴍᴏɴᴛʜ 324 | 3. 55₹ = 3ᴍᴏɴᴛʜ 325 | 4. 110₹ = 6ᴍᴏɴᴛʜ 326 | 327 | ========================== 328 | 🎁 ᴘʀᴇᴍɪᴜᴍ ғᴇᴀᴛᴜʀᴇs : 329 | 330 | ○ sᴇᴀʀᴄʜ ᴍᴏᴠɪᴇ ɪɴ ᴛʜᴇ ʙᴏᴛ 331 | ○ ɴᴏ ғɪʟᴇ ʟɪᴍɪᴛs 332 | ○ ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ғɪʟᴇs 333 | ○ ɴᴏ ʟɪᴍɪᴛs ғᴏʀ sᴇɴᴅ ᴀʟʟ ʙᴜᴛᴛᴏɴ 334 | ○ ɴᴏ ɴᴇᴇᴅ ᴛᴏ ᴏᴘᴇɴ ʟɪɴᴋꜱ 335 | ○ ɴᴏ ɴᴇᴇᴅ ᴠᴇʀɪғʏ 336 | ○ ᴅɪʀᴇᴄᴛ ғɪʟᴇs 337 | ○ ᴀᴅ-ғʀᴇᴇ ᴇxᴘᴇʀɪᴇɴᴄᴇ 338 | ○ ᴜɴʟɪᴍɪᴛᴇᴅ ᴍᴏᴠɪᴇs & sᴇʀɪᴇs 339 | 340 | ========================== 341 | ➛ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀᴄᴛɪᴠᴇ ᴘʟᴀɴ ʙʏ ᴜꜱɪɴɢ : /myplan 342 | 343 | ‼️ ᴍᴜsᴛ sᴇɴᴅ sᴄʀᴇᴇɴsʜᴏᴛ ᴀғᴛᴇʀ ᴘᴀʏᴍᴇɴᴛ""" 344 | 345 | 346 | UPI_TXT = """ 347 | ⚜️ ᴘᴀʏ ᴀᴍᴍᴏᴜɴᴛ ᴀᴄᴄᴏʀᴅɪɴɢ ᴛᴏ ʏᴏᴜʀ ᴘʟᴀɴ ᴀɴᴅ ᴇɴᴊᴏʏ ᴘʀᴇᴍɪᴜᴍ ᴍᴇᴍʙᴇʀꜱʜɪᴘ ! 348 | 349 | 💵 ᴜᴘɪ ɪᴅ - JEETUBIND@paytm 350 | 351 | ‼️ ᴍᴜsᴛ sᴇɴᴅ sᴄʀᴇᴇɴsʜᴏᴛ ᴀғᴛᴇʀ ᴘᴀʏᴍᴇɴᴛ 352 | पेमेंट होने के बाद हमे स्क्रीन शॉट भेजें.""" 353 | 354 | QR_TXT = """ 355 | ⚜️ ᴘᴀʏ ᴀᴍᴍᴏᴜɴᴛ ᴀᴄᴄᴏʀᴅɪɴɢ ᴛᴏ ʏᴏᴜʀ ᴘʟᴀɴ ᴀɴᴅ ᴇɴᴊᴏʏ ᴘʀᴇᴍɪᴜᴍ ᴍᴇᴍʙᴇʀꜱʜɪᴘ ! 356 | 357 | 358 | ‼️ ᴍᴜsᴛ sᴇɴᴅ sᴄʀᴇᴇɴsʜᴏᴛ ᴀғᴛᴇʀ ᴘᴀʏᴍᴇɴᴛ 359 | पेमेंट होने के बाद हमे स्क्रीन शॉट भेजें.""" 360 | 361 | FREE_TXT = """👋 ʜᴇʏ {}, 362 | 363 | 🥳 ᴄᴏɴɢʀᴀᴛᴜʟᴀᴛɪᴏɴꜱ 364 | 365 | 🎉 ʏᴏᴜ ᴄᴀɴ ᴜsᴇ ꜰʀᴇᴇ ᴘʀᴇᴍɪᴜᴍ ᴛʀᴀɪʟ ꜰᴏʀ 5 ᴍɪɴᴜᴛᴇs 366 | 367 | sᴇᴀʀᴄʜ🔍 ᴍᴏᴠɪᴇ ᴀɢᴀɪɴ ꜰʀᴏᴍ ɴᴏᴡ !""" 368 | 369 | 370 | NOT_AVAILABLE_TXT = """{} 371 | 372 | ʏᴏᴜʀ ʀᴇǫᴜᴇsᴛᴇᴅ ᴄᴏɴᴛᴇɴᴛ ɴᴏᴛ ᴀᴠᴀɪʟᴀʙʟᴇ""" 373 | 374 | SERIES_FORMAT_TXT = """{} 375 | 376 | ʏᴏᴜʀ ʀᴇǫᴜᴇsᴛ ғᴏʀᴍᴀᴛ ᴡʀᴏɴɢ❌ 377 | ғᴏʟʟᴏᴡ ᴛʜɪs ғᴏʀᴍᴀᴛ 👇 378 | 379 | Money heist S01E01 380 | Money heist S01""" 381 | 382 | UPLOADED_TXT = """{} 383 | 384 | ʏᴏᴜʀ ʀᴇǫᴜᴇsᴛᴇᴅ ᴄᴏɴᴛᴇɴᴛ ᴜᴘʟᴏᴀᴅᴇᴅ ✅ 385 | sᴇᴀʀᴄʜ 🔍 ᴀɢᴀɪɴ ᴀɴᴅ ɪɴᴊᴏʏ""" 386 | 387 | NOT_RELEASE_TXT = """{} 388 | 389 | ʏᴏᴜʀ ʀᴇǫᴜᴇsᴛᴇᴅ ᴄᴏɴᴛᴇɴᴛ ɴᴏᴛ ʀᴇʟᴇᴀsᴇ 390 | ᴘʟᴇᴀsᴇ🙏 ᴡᴀɪᴛ ᴛʜᴇ ʀᴇʟᴇᴀsᴇ ᴅᴀʏ""" 391 | 392 | SPELL_TXT = """{} 393 | ʏᴏᴜʀ ʀᴇǫᴜᴇsᴛᴇᴅ ᴄᴏɴᴛᴇɴᴛ ɴᴀᴍᴇ ɴᴏᴛ ᴍᴀᴛᴄʜ ᴀɴʏ sᴇʀɪᴇs ᴏʀ ᴍᴏᴠɪᴇ ɴᴀᴍᴇ 394 | 395 | ᴘʟᴇᴀsᴇ ʀᴇǫᴜᴇsᴛ ᴄᴏʀʀᴇᴄᴛ ɴᴀᴍᴇ""" 396 | 397 | 398 | BROADCAST = """{} 399 | 400 | Total: `{}` 401 | Remaining: `{}` 402 | Success: `{}` 403 | Failed: `{}`""" 404 | 405 | RESTART_TXT = """ 406 | Bᴏᴛ Rᴇsᴛᴀʀᴛᴇᴅ ! 407 | 408 | 🤖 Bᴏᴛ : {} 409 | 📅 Dᴀᴛᴇ : {} 410 | ⏰ Tɪᴍᴇ : {} 411 | 🌐 Tɪᴍᴇᴢᴏɴᴇ : Asia/Kolkata 412 | 🛠️ Bᴜɪʟᴅ Sᴛᴀᴛᴜs: v2.7.1 [ Sᴛᴀʙʟᴇ ]""" 413 | 414 | LOGO = """ 415 | ░██████╗░█████╗░███████╗░█████╗░██████╗░██╗ 416 | ██╔════╝██╔══██╗██╔════╝██╔══██╗██╔══██╗██║ 417 | ╚█████╗░███████║█████╗░░███████║██████╔╝██║ 418 | ░╚═══██╗██╔══██║██╔══╝░░██╔══██║██╔══██╗██║ 419 | ██████╔╝██║░░██║██║░░░░░██║░░██║██║░░██║██║ 420 | ╚═════╝░╚═╝░░╚═╝╚═╝░░░░░╚═╝░░╚═╝╚═╝░░╚═╝╚═╝ 421 | 422 | BOT SUCCESSFULLY STARTED 💥 ✅✅✅✅✅✅✅✅✅""" 423 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import logging 4 | from pyrogram.errors import InputUserDeactivated, UserNotParticipant, FloodWait, UserIsBlocked, PeerIdInvalid, ChatAdminRequired, MessageIdInvalid, EmoticonInvalid, ReactionInvalid 5 | from info import * 6 | from imdb import Cinemagoer 7 | import asyncio 8 | from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup 9 | from pyrogram import enums 10 | from typing import Union 11 | from Script import script 12 | import pytz 13 | import random 14 | from random import choice 15 | from asyncio import sleep 16 | import time 17 | import re 18 | import os 19 | from datetime import datetime, timedelta, date, time 20 | import string 21 | from typing import List 22 | from database.users_chats_db import db 23 | from bs4 import BeautifulSoup 24 | import requests 25 | import aiohttp 26 | from shortzy import Shortzy 27 | 28 | logger = logging.getLogger(__name__) 29 | logger.setLevel(logging.INFO) 30 | 31 | BTN_URL_REGEX = re.compile( 32 | r"(\[([^\[]+?)\]\((buttonurl|buttonalert):(?:/{0,2})(.+?)(:same)?\))" 33 | ) 34 | 35 | imdb = Cinemagoer() 36 | BANNED = {} 37 | SMART_OPEN = '“' 38 | SMART_CLOSE = '”' 39 | START_CHAR = ('\'', '"', SMART_OPEN) 40 | 41 | # temp db for banned 42 | class temp(object): 43 | BANNED_USERS = [] 44 | BANNED_CHATS = [] 45 | ME = None 46 | CURRENT=int(os.environ.get("SKIP", 2)) 47 | CANCEL = False 48 | MELCOW = {} 49 | U_NAME = None 50 | B_NAME = None 51 | SETTINGS = {} 52 | KEYWORD = {} 53 | GETALL = {} 54 | SPELL_CHECK = {} 55 | IMDB_CAP = {} 56 | CHAT = {} 57 | 58 | async def check_reset_time(): 59 | tz = pytz.timezone('Asia/Kolkata') 60 | while True: 61 | now = datetime.now(tz) 62 | target_time = time(23, 59) 63 | target_datetime = tz.localize(datetime.combine(now.date(), target_time)) 64 | if now > target_datetime: 65 | target_datetime += timedelta(days=1) 66 | time_diff = (target_datetime - now).total_seconds() 67 | hours = time_diff // 3600 68 | minutes = (time_diff % 3600) // 60 69 | seconds = time_diff % 60 70 | logging.info(f"Next reset in {int(hours)} hours, {int(minutes)} minutes, and {int(seconds)} seconds.") 71 | await asyncio.sleep(time_diff) 72 | await db.reset_all_files_count() 73 | await db.reset_allsend_files() 74 | logging.info("Files count and send count reset successfully") 75 | 76 | async def get_seconds(time_string): 77 | def extract_value_and_unit(ts): 78 | value = "" 79 | unit = "" 80 | 81 | index = 0 82 | while index < len(ts) and ts[index].isdigit(): 83 | value += ts[index] 84 | index += 1 85 | 86 | unit = ts[index:].lstrip() 87 | 88 | if value: 89 | value = int(value) 90 | 91 | return value, unit 92 | 93 | value, unit = extract_value_and_unit(time_string) 94 | 95 | if unit == 's': 96 | return value 97 | elif unit == 'min': 98 | return value * 60 99 | elif unit == 'hour': 100 | return value * 3600 101 | elif unit == 'day': 102 | return value * 86400 103 | elif unit == 'month': 104 | return value * 86400 * 30 105 | elif unit == 'year': 106 | return value * 86400 * 365 107 | else: 108 | return 0 109 | 110 | async def is_req_subscribed(bot, query): 111 | if await db.find_join_req(query.from_user.id): 112 | return True 113 | try: 114 | user = await bot.get_chat_member(AUTH_CHANNEL, query.from_user.id) 115 | except UserNotParticipant: 116 | pass 117 | except Exception as e: 118 | print(e) 119 | else: 120 | if user.status != enums.ChatMemberStatus.BANNED: 121 | return True 122 | return False 123 | 124 | async def is_subscribed(bot, user_id, channel_id): 125 | try: 126 | user = await bot.get_chat_member(channel_id, user_id) 127 | except UserNotParticipant: 128 | pass 129 | except Exception as e: 130 | pass 131 | else: 132 | if user.status != enums.ChatMemberStatus.BANNED: 133 | return True 134 | return False 135 | 136 | async def get_poster(query, bulk=False, id=False, file=None): 137 | if not id: 138 | # https://t.me/GetTGLink/4183 139 | query = (query.strip()).lower() 140 | title = query 141 | year = re.findall(r'[1-2]\d{3}$', query, re.IGNORECASE) 142 | if year: 143 | year = list_to_str(year[:1]) 144 | title = (query.replace(year, "")).strip() 145 | elif file is not None: 146 | year = re.findall(r'[1-2]\d{3}', file, re.IGNORECASE) 147 | if year: 148 | year = list_to_str(year[:1]) 149 | else: 150 | year = None 151 | movieid = imdb.search_movie(title.lower(), results=10) 152 | if not movieid: 153 | return None 154 | if year: 155 | filtered=list(filter(lambda k: str(k.get('year')) == str(year), movieid)) 156 | if not filtered: 157 | filtered = movieid 158 | else: 159 | filtered = movieid 160 | movieid=list(filter(lambda k: k.get('kind') in ['movie', 'tv series'], filtered)) 161 | if not movieid: 162 | movieid = filtered 163 | if bulk: 164 | return movieid 165 | movieid = movieid[0].movieID 166 | else: 167 | movieid = query 168 | movie = imdb.get_movie(movieid) 169 | if movie.get("original air date"): 170 | date = movie["original air date"] 171 | elif movie.get("year"): 172 | date = movie.get("year") 173 | else: 174 | date = "N/A" 175 | plot = "" 176 | if not LONG_IMDB_DESCRIPTION: 177 | plot = movie.get('plot') 178 | if plot and len(plot) > 0: 179 | plot = plot[0] 180 | else: 181 | plot = movie.get('plot outline') 182 | if plot and len(plot) > 800: 183 | plot = plot[0:800] + "..." 184 | 185 | return { 186 | 'title': movie.get('title'), 187 | 'votes': movie.get('votes'), 188 | "aka": list_to_str(movie.get("akas")), 189 | "seasons": movie.get("number of seasons"), 190 | "box_office": movie.get('box office'), 191 | 'localized_title': movie.get('localized title'), 192 | 'kind': movie.get("kind"), 193 | "imdb_id": f"tt{movie.get('imdbID')}", 194 | "cast": list_to_str(movie.get("cast")), 195 | "runtime": list_to_str(movie.get("runtimes")), 196 | "countries": list_to_str(movie.get("countries")), 197 | "certificates": list_to_str(movie.get("certificates")), 198 | "languages": list_to_str(movie.get("languages")), 199 | "director": list_to_str(movie.get("director")), 200 | "writer":list_to_str(movie.get("writer")), 201 | "producer":list_to_str(movie.get("producer")), 202 | "composer":list_to_str(movie.get("composer")) , 203 | "cinematographer":list_to_str(movie.get("cinematographer")), 204 | "music_team": list_to_str(movie.get("music department")), 205 | "distributors": list_to_str(movie.get("distributors")), 206 | 'release_date': date, 207 | 'year': movie.get('year'), 208 | 'genres': list_to_str(movie.get("genres")), 209 | 'poster': movie.get('full-size cover url'), 210 | 'plot': plot, 211 | 'rating': str(movie.get("rating")), 212 | 'url':f'https://www.imdb.com/title/tt{movieid}' 213 | } 214 | # https://github.com/odysseusmax/animated-lamp/blob/2ef4730eb2b5f0596ed6d03e7b05243d93e3415b/bot/utils/broadcast.py#L37 215 | 216 | async def broadcast_messages(user_id, message): 217 | try: 218 | await message.copy(chat_id=user_id) 219 | return True, "Success" 220 | except FloodWait as e: 221 | await asyncio.sleep(e.x) 222 | return await broadcast_messages(user_id, message) 223 | except InputUserDeactivated: 224 | await db.delete_user(int(user_id)) 225 | logging.info(f"{user_id} - Removed from Database, since deleted account.") 226 | return False, "Deleted" 227 | except UserIsBlocked: 228 | logging.info(f"{user_id} - Blocked the bot.") 229 | return False, "Blocked" 230 | except PeerIdInvalid: 231 | await db.delete_user(int(user_id)) 232 | logging.info(f"{user_id} - PeerIdInvalid") 233 | return False, "Error" 234 | except Exception as e: 235 | return False, "Error" 236 | 237 | async def get_settings(group_id): 238 | settings = temp.SETTINGS.get(group_id) 239 | if not settings: 240 | settings = await db.get_settings(group_id) 241 | temp.SETTINGS[group_id] = settings 242 | return settings 243 | 244 | async def save_group_settings(group_id, key, value): 245 | current = await get_settings(group_id) 246 | current[key] = value 247 | temp.SETTINGS[group_id] = current 248 | await db.update_settings(group_id, current) 249 | 250 | def get_size(size): 251 | """Get size in readable format""" 252 | 253 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"] 254 | size = float(size) 255 | i = 0 256 | while size >= 1024.0 and i < len(units): 257 | i += 1 258 | size /= 1024.0 259 | return "%.2f %s" % (size, units[i]) 260 | 261 | def list_to_str(k): 262 | if not k: 263 | return "N/A" 264 | elif len(k) == 1: 265 | return str(k[0]) 266 | else: 267 | return ' '.join(f'{elem}, ' for elem in k) 268 | 269 | def get_file_id(msg: Message): 270 | if msg.media: 271 | for message_type in ( 272 | "photo", 273 | "animation", 274 | "audio", 275 | "document", 276 | "video", 277 | "video_note", 278 | "voice", 279 | "sticker" 280 | ): 281 | obj = getattr(msg, message_type) 282 | if obj: 283 | setattr(obj, "message_type", message_type) 284 | return obj 285 | 286 | def extract_user(message: Message) -> Union[int, str]: 287 | """extracts the user from a message""" 288 | # https://github.com/SpEcHiDe/PyroGramBot/blob/f30e2cca12002121bad1982f68cd0ff9814ce027/pyrobot/helper_functions/extract_user.py#L7 289 | user_id = None 290 | user_first_name = None 291 | if message.reply_to_message: 292 | user_id = message.reply_to_message.from_user.id 293 | user_first_name = message.reply_to_message.from_user.first_name 294 | 295 | elif len(message.command) > 1: 296 | if ( 297 | len(message.entities) > 1 and 298 | message.entities[1].type == enums.MessageEntityType.TEXT_MENTION 299 | ): 300 | 301 | required_entity = message.entities[1] 302 | user_id = required_entity.user.id 303 | user_first_name = required_entity.user.first_name 304 | else: 305 | user_id = message.command[1] 306 | # don't want to make a request -_- 307 | user_first_name = user_id 308 | try: 309 | user_id = int(user_id) 310 | except ValueError: 311 | pass 312 | else: 313 | user_id = message.from_user.id 314 | user_first_name = message.from_user.first_name 315 | return (user_id, user_first_name) 316 | 317 | 318 | async def stream_site(link, grp_id): 319 | try: 320 | settings = await get_settings(grp_id) if await get_settings(grp_id) else {} 321 | api_key, site_key = ('streamapi', 'streamsite') 322 | default_api, default_site = STREAM_API, STREAM_SITE 323 | 324 | api = settings.get(api_key, default_api) 325 | site = settings.get(site_key, default_site) 326 | 327 | shortzy = Shortzy(api, site) 328 | 329 | try: 330 | link = await shortzy.convert(link) 331 | except Exception: 332 | link = await shortzy.get_quick_link(link) 333 | return link 334 | except Exception as e: 335 | logger.error(e) 336 | 337 | async def get_shortlink(link, grp_id, is_second_shortener=False, is_third_shortener=False): 338 | settings = await get_settings(grp_id) if await get_settings(grp_id) else {} 339 | if is_third_shortener: 340 | api_key, site_key = ('verify_api3', 'verify_3') 341 | default_api, default_site = VERIFY_API3, VERIFY_URL3 342 | elif is_second_shortener: 343 | api_key, site_key = ('verify_api2', 'verify_2') 344 | default_api, default_site = VERIFY_API2, VERIFY_URL2 345 | else: 346 | api_key, site_key = ('verify_api', 'verify') 347 | default_api, default_site = VERIFY_API, VERIFY_URL 348 | 349 | api = settings.get(api_key, default_api) 350 | site = settings.get(site_key, default_site) 351 | shortzy = Shortzy(api, site) 352 | try: 353 | link = await shortzy.convert(link) 354 | except Exception: 355 | link = await shortzy.get_quick_link(link) 356 | return link 357 | 358 | async def get_users(): 359 | count = await user_col.count_documents({}) 360 | cursor = user_col.find({}) 361 | list = await cursor.to_list(length=int(count)) 362 | return count, list 363 | 364 | async def get_text(settings, remaining_seconds, files, query, total_results, search): 365 | try: 366 | if settings["imdb"]: 367 | IMDB_CAP = temp.IMDB_CAP.get(query.from_user.id) 368 | CAPTION = f"☠️ ᴛɪᴛʟᴇ : {search}\n📂 ᴛᴏᴛᴀʟ ꜰɪʟᴇꜱ : {total_results}\n📝 ʀᴇǫᴜᴇsᴛᴇᴅ ʙʏ : {query.from_user.first_name}\n⏰ ʀᴇsᴜʟᴛ ɪɴ : {remaining_seconds} Sᴇᴄᴏɴᴅs\n\n" 369 | if IMDB_CAP: 370 | cap = IMDB_CAP 371 | for file in files: #shortlink = false, imdb = true 372 | cap += f"\n\n📁 {get_size(file.file_size)} ▷ {file.file_name}" 373 | else: 374 | imdb = await get_poster(search, file=(files[0]).file_name) if settings["imdb"] else None 375 | if imdb: 376 | TEMPLATE = script.IMDB_TEMPLATE_TXT 377 | cap = TEMPLATE.format( 378 | qurey=search, 379 | title=imdb['title'], 380 | votes=imdb['votes'], 381 | aka=imdb["aka"], 382 | seasons=imdb["seasons"], 383 | box_office=imdb['box_office'], 384 | localized_title=imdb['localized_title'], 385 | kind=imdb['kind'], 386 | imdb_id=imdb["imdb_id"], 387 | cast=imdb["cast"], 388 | runtime=imdb["runtime"], 389 | countries=imdb["countries"], 390 | certificates=imdb["certificates"], 391 | languages=imdb["languages"], 392 | director=imdb["director"], 393 | writer=imdb["writer"], 394 | producer=imdb["producer"], 395 | composer=imdb["composer"], 396 | cinematographer=imdb["cinematographer"], 397 | music_team=imdb["music_team"], 398 | distributors=imdb["distributors"], 399 | release_date=imdb['release_date'], 400 | year=imdb['year'], 401 | genres=imdb['genres'], 402 | poster=imdb['poster'], 403 | plot=imdb['plot'], 404 | rating=imdb['rating'], 405 | url=imdb['url'], 406 | **locals() 407 | ) 408 | for file in files: 409 | cap += f"\n\n📁 {get_size(file.file_size)} ▷ {file.file_name}" 410 | else: 411 | cap = f"{CAPTION}" #imdb = false 412 | cap+="📚 Your Requested Files 👇\n\n" 413 | for file in files: 414 | cap += f"📁 {get_size(file.file_size)} ▷ {file.file_name}\n\n" 415 | 416 | else: 417 | #imdb = false 418 | cap = f"☠️ ᴛɪᴛʟᴇ : {search}\n📂 ᴛᴏᴛᴀʟ ꜰɪʟᴇꜱ : {total_results}\n📝 ʀᴇǫᴜᴇsᴛᴇᴅ ʙʏ : {query.from_user.first_name}\n⏰ ʀᴇsᴜʟᴛ ɪɴ : {remaining_seconds}\n\n" 419 | cap+="📚 Your Requested Files 👇\n\n" 420 | for file in files: 421 | cap += f"📁 {get_size(file.file_size)} ▷ {file.file_name}\n\n" 422 | return cap 423 | except Exception as e: 424 | await query.answer(f"{e}", show_alert=True) 425 | return cap 426 | -------------------------------------------------------------------------------- /database/users_chats_db.py: -------------------------------------------------------------------------------- 1 | # This code has been modified by @Safaridev 2 | # Please do not remove this credit 3 | import motor.motor_asyncio 4 | from info import DATABASE_NAME, DATABASE_URI, IMDB, IMDB_TEMPLATE, MELCOW_NEW_USERS, SINGLE_BUTTON, SPELL_CHECK_REPLY, AUTO_DELETE, MAX_BTN, AUTO_FFILTER, TUTORIAL, TUTORIAL2, TUTORIAL3, REFERAL_TIME, STREAM_API, STREAM_SITE, VERIFY_URL, VERIFY_API, \ 5 | VERIFY_URL2, VERIFY_API2, VERIFY_URL3, VERIFY_API3, LIMIT_MODE, TWO_VERIFY_GAP, THIRD_VERIFY_GAP, STREAM_MODE, LOG_CHANNEL, IS_VERIFY, AUTH_CHANNEL, CUSTOM_FILE_CAPTION, FILE_LIMITE, SEND_ALL_LIMITE, STREAM_SITE, STREAM_API 6 | from datetime import datetime, timedelta 7 | import pytz 8 | import re 9 | import time 10 | import hashlib 11 | import random 12 | import string 13 | 14 | class Database: 15 | 16 | def __init__(self, uri, database_name): 17 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri) 18 | self.db = self._client[database_name] 19 | self.col = self.db.users 20 | self.grp = self.db.groups 21 | self.users = self.db.uersz 22 | self.codes = self.db.codes 23 | self.safari = self.db.safari 24 | self.req = self.db.requests 25 | self.links_col = self.db.links 26 | self.verify_id = self.db.verify_id 27 | self.settings_col = self.db.settings 28 | 29 | def new_user(self, id, name): 30 | return dict( 31 | id = id, 32 | name = name, 33 | send_all=0, 34 | files_count=0, 35 | lifetime_files=0, 36 | ban_status=dict( 37 | is_banned=False, 38 | ban_reason="", 39 | ), 40 | ) 41 | 42 | def new_group(self, id, title, owner_id): 43 | return dict( 44 | id = id, 45 | title = title, 46 | owner_id=owner_id, 47 | is_verified=False, 48 | is_rejected=False, 49 | chat_status=dict( 50 | is_disabled=False, 51 | reason="", 52 | ), 53 | ) 54 | 55 | async def get_setting(self, key, default=None): 56 | setting = await self.settings_col.find_one({"name": key}) 57 | return setting.get("value", default) if setting else default 58 | 59 | async def set_setting(self, key, value): 60 | await self.settings_col.update_one( 61 | {"name": key}, 62 | {"$set": {"value": value}}, 63 | upsert=True) 64 | 65 | async def find_join_req(self, id): 66 | return bool(await self.req.find_one({'id': id})) 67 | 68 | async def add_join_req(self, id): 69 | await self.req.insert_one({'id': id}) 70 | 71 | async def del_join_req(self): 72 | await self.req.drop() 73 | 74 | async def get_safari_user(self, user_id): 75 | user_id = int(user_id) 76 | user = await self.safari.find_one({"user_id": user_id}) 77 | ist_timezone = pytz.timezone('Asia/Kolkata') 78 | if not user: 79 | res = { 80 | "user_id": user_id, 81 | "last_verified": datetime(2020, 5, 17, 0, 0, 0, tzinfo=ist_timezone), 82 | "second_verified": datetime(2019, 5, 17, 0, 0, 0, tzinfo=ist_timezone), 83 | } 84 | user = await self.safari.insert_one(res) 85 | return user 86 | 87 | async def update_safari_user(self, user_id, value:dict): 88 | user_id = int(user_id) 89 | myquery = {"user_id": user_id} 90 | newvalues = {"$set": value} 91 | return await self.safari.update_one(myquery, newvalues) 92 | 93 | async def is_user_verified(self, user_id): 94 | user = await self.get_safari_user(user_id) 95 | try: 96 | safariback = user["last_verified"] 97 | except Exception: 98 | user = await self.get_safari_user(user_id) 99 | safariback = user["last_verified"] 100 | ist_timezone = pytz.timezone('Asia/Kolkata') 101 | safariback = safariback.astimezone(ist_timezone) 102 | current_time = datetime.now(tz=ist_timezone) 103 | seconds_since_midnight = (current_time - datetime(current_time.year, current_time.month, current_time.day, 0, 0, 0, tzinfo=ist_timezone)).total_seconds() 104 | time_diff = current_time - safariback 105 | total_seconds = time_diff.total_seconds() 106 | return total_seconds <= seconds_since_midnight 107 | 108 | async def user_verified(self, user_id): 109 | user = await self.get_safari_user(user_id) 110 | try: 111 | safariback = user["second_verified"] 112 | except Exception: 113 | user = await self.get_safari_user(user_id) 114 | safariback = user["second_verified"] 115 | ist_timezone = pytz.timezone('Asia/Kolkata') 116 | safariback = safariback.astimezone(ist_timezone) 117 | current_time = datetime.now(tz=ist_timezone) 118 | seconds_since_midnight = (current_time - datetime(current_time.year, current_time.month, current_time.day, 0, 0, 0, tzinfo=ist_timezone)).total_seconds() 119 | time_diff = current_time - safariback 120 | total_seconds = time_diff.total_seconds() 121 | return total_seconds <= seconds_since_midnight 122 | 123 | async def use_second_shortener(self, user_id, time): 124 | user = await self.get_safari_user(user_id) 125 | if not user.get("second_verified"): 126 | ist_timezone = pytz.timezone('Asia/Kolkata') 127 | await self.update_safari_user(user_id, {"second_verified":datetime(2019, 5, 17, 0, 0, 0, tzinfo=ist_timezone)}) 128 | user = await self.get_safari_user(user_id) 129 | if await self.is_user_verified(user_id): 130 | try: 131 | safariback = user["last_verified"] 132 | except Exception: 133 | user = await self.get_safari_user(user_id) 134 | safariback = user["last_verified"] 135 | ist_timezone = pytz.timezone('Asia/Kolkata') 136 | safariback = safariback.astimezone(ist_timezone) 137 | current_time = datetime.now(tz=ist_timezone) 138 | time_difference = current_time - safariback 139 | if time_difference > timedelta(seconds=time): 140 | safariback = user["last_verified"].astimezone(ist_timezone) 141 | second_time = user["second_verified"].astimezone(ist_timezone) 142 | return second_time < safariback 143 | return False 144 | 145 | async def use_third_shortener(self, user_id, time): 146 | user = await self.get_safari_user(user_id) 147 | if not user.get("third_verified"): 148 | ist_timezone = pytz.timezone('Asia/Kolkata') 149 | await self.update_safari_user(user_id, {"third_verified":datetime(2018, 5, 17, 0, 0, 0, tzinfo=ist_timezone)}) 150 | user = await self.get_safari_user(user_id) 151 | if await self.user_verified(user_id): 152 | try: 153 | safariback = user["second_verified"] 154 | except Exception: 155 | user = await self.get_safari_user(user_id) 156 | safariback = user["second_verified"] 157 | ist_timezone = pytz.timezone('Asia/Kolkata') 158 | safariback = safariback.astimezone(ist_timezone) 159 | current_time = datetime.now(tz=ist_timezone) 160 | time_difference = current_time - safariback 161 | if time_difference > timedelta(seconds=time): 162 | safariback = user["second_verified"].astimezone(ist_timezone) 163 | second_time = user["third_verified"].astimezone(ist_timezone) 164 | return second_time < safariback 165 | return False 166 | 167 | async def create_verify_id(self, user_id: int, hash): 168 | res = {"user_id": user_id, "hash":hash, "verified":False} 169 | return await self.verify_id.insert_one(res) 170 | 171 | async def get_verify_id_info(self, user_id: int, hash): 172 | return await self.verify_id.find_one({"user_id": user_id, "hash": hash}) 173 | 174 | async def update_verify_id_info(self, user_id, hash, value: dict): 175 | myquery = {"user_id": user_id, "hash": hash} 176 | newvalues = { "$set": value } 177 | return await self.verify_id.update_one(myquery, newvalues) 178 | 179 | async def add_user(self, id, name): 180 | user = self.new_user(id, name) 181 | await self.col.insert_one(user) 182 | 183 | async def is_user_exist(self, id): 184 | user = await self.col.find_one({'id': int(id)}) 185 | return bool(user) 186 | 187 | async def total_users_count(self): 188 | count = await self.col.count_documents({}) 189 | return count 190 | 191 | async def remove_ban(self, id): 192 | ban_status = dict( 193 | is_banned=False, 194 | ban_reason='' 195 | ) 196 | await self.col.update_one({'id': id}, {'$set': {'ban_status': ban_status}}) 197 | 198 | async def ban_user(self, user_id, ban_reason="No Reason"): 199 | ban_status = dict( 200 | is_banned=True, 201 | ban_reason=ban_reason 202 | ) 203 | await self.col.update_one({'id': user_id}, {'$set': {'ban_status': ban_status}}) 204 | 205 | async def get_ban_status(self, id): 206 | default = dict( 207 | is_banned=False, 208 | ban_reason='' 209 | ) 210 | user = await self.col.find_one({'id':int(id)}) 211 | if not user: 212 | return default 213 | return user.get('ban_status', default) 214 | 215 | async def get_all_users(self): 216 | return self.col.find({}) 217 | 218 | 219 | async def delete_user(self, user_id): 220 | await self.col.delete_many({'id': int(user_id)}) 221 | 222 | 223 | async def get_banned(self): 224 | users = self.col.find({'ban_status.is_banned': True}) 225 | chats = self.grp.find({'chat_status.is_disabled': True}) 226 | b_chats = [chat['id'] async for chat in chats] 227 | b_users = [user['id'] async for user in users] 228 | return b_users, b_chats 229 | 230 | async def files_count(self, user_id, key): 231 | user = await self.col.find_one({"id": user_id}) 232 | if user is None: 233 | await self.add_user(user_id, "None") 234 | return 0 235 | return user.get(key, 0) 236 | 237 | async def update_files(self, user_id, key, value): 238 | await self.col.update_one({"id": user_id}, {"$set": {key: value}}) 239 | 240 | async def reset_all_files_count(self): 241 | await self.col.update_many({}, {"$set": {"files_count": 0}}) 242 | 243 | async def reset_allsend_files(self): 244 | await self.col.update_many({}, {"$set": {"send_all": 0}}) 245 | 246 | async def reset_daily_files_count(self, user_id): 247 | user = await self.col.find_one({"id": user_id}) 248 | if user is None: 249 | return 250 | await self.col.update_one({"id": user_id}, {"$set": {"files_coun": 0}}) 251 | 252 | async def add_chat(self, chat, title, owner_id): 253 | chat = self.new_group(chat, title, owner_id) 254 | await self.grp.insert_one(chat) 255 | 256 | async def get_chat(self, chat_id): 257 | chat = await self.grp.find_one({'id': int(chat_id)}) 258 | return chat if chat else False 259 | 260 | 261 | async def re_enable_chat(self, id): 262 | chat_status=dict( 263 | is_disabled=False, 264 | reason="", 265 | ) 266 | await self.grp.update_one({'id': int(id)}, {'$set': {'chat_status': chat_status}}) 267 | 268 | async def update_settings(self, id, settings): 269 | await self.grp.update_one({'id': int(id)}, {'$set': {'settings': settings}}) 270 | 271 | async def get_settings(self, id): 272 | default = { 273 | 'button': SINGLE_BUTTON, 274 | 'imdb': IMDB, 275 | 'spell_check': SPELL_CHECK_REPLY, 276 | 'welcome': MELCOW_NEW_USERS, 277 | 'auto_delete': AUTO_DELETE, 278 | 'auto_ffilter': AUTO_FFILTER, 279 | 'max_btn': MAX_BTN, 280 | 'template': IMDB_TEMPLATE, 281 | 'verify': VERIFY_URL, 282 | 'verify_api': VERIFY_API, 283 | 'verify_2': VERIFY_URL2, 284 | 'verify_api2': VERIFY_API2, 285 | 'verify_3': VERIFY_URL3, 286 | 'verify_api3': VERIFY_API3, 287 | 'verify_time': TWO_VERIFY_GAP, 288 | 'verify_time2': THIRD_VERIFY_GAP, 289 | 'tutorial': TUTORIAL, 290 | 'tutorial2': TUTORIAL2, 291 | 'tutorial3': TUTORIAL3, 292 | 'filelock': LIMIT_MODE, 293 | 'log': LOG_CHANNEL, 294 | 'is_verify': IS_VERIFY, 295 | 'fsub_id': AUTH_CHANNEL, 296 | 'file_limit': FILE_LIMITE, 297 | 'all_limit': SEND_ALL_LIMITE, 298 | 'stream_mode': STREAM_MODE, 299 | 'streamapi': STREAM_API, 300 | 'streamsite': STREAM_SITE, 301 | 'caption': CUSTOM_FILE_CAPTION 302 | } 303 | chat = await self.grp.find_one({'id':int(id)}) 304 | if chat: 305 | return chat.get('settings', default) 306 | return default 307 | 308 | 309 | async def disable_chat(self, chat, reason="No Reason"): 310 | chat_status=dict( 311 | is_disabled=True, 312 | reason=reason, 313 | ) 314 | await self.grp.update_one({'id': int(chat)}, {'$set': {'chat_status': chat_status}}) 315 | 316 | async def verify_group(self, chat_id): 317 | await self.grp.update_one({'id': int(chat_id)}, {'$set': {'is_verified': True}}) 318 | 319 | async def un_rejected(self, chat_id): 320 | await self.grp.update_one({'id': int(chat_id)}, {'$set': {'is_rejected': False}}) 321 | 322 | async def reject_group(self, chat_id): 323 | await self.grp.update_one({'id': int(chat_id)}, {'$set': {'is_rejected': True}}) 324 | 325 | async def check_group_verification(self, chat_id): 326 | chat = await self.get_chat(chat_id) 327 | if not chat: 328 | return False 329 | return chat.get('is_verified') 330 | 331 | async def rejected_group(self, chat_id): 332 | chat = await self.get_chat(chat_id) 333 | if not chat: 334 | return False 335 | return chat.get('is_rejected') 336 | 337 | async def get_all_groups(self): 338 | return await self.grp.find().to_list(None) 339 | 340 | async def delete_all_groups(self): 341 | await self.grp.delete_many({}) 342 | 343 | async def total_chat_count(self): 344 | count = await self.grp.count_documents({}) 345 | return count 346 | 347 | 348 | async def get_all_chats(self): 349 | return self.grp.find({}) 350 | 351 | 352 | async def get_db_size(self): 353 | return (await self.db.command("dbstats"))['dataSize'] 354 | 355 | async def get_user(self, user_id): 356 | user_data = await self.users.find_one({"id": user_id}) 357 | return user_data 358 | 359 | async def update_user(self, user_data): 360 | await self.users.update_one({"id": user_data["id"]}, {"$set": user_data}, upsert=True) 361 | 362 | async def has_premium_access(self, user_id): 363 | user_data = await self.get_user(user_id) 364 | if user_data: 365 | expiry_time = user_data.get("expiry_time") 366 | if expiry_time is None: 367 | return False 368 | elif isinstance(expiry_time, datetime) and datetime.now() <= expiry_time: 369 | return True 370 | else: 371 | await self.users.update_one({"id": user_id}, {"$set": {"expiry_time": None}}) 372 | return False 373 | 374 | async def update_one(self, filter_query, update_data): 375 | try: 376 | result = await self.users.update_one(filter_query, update_data) 377 | return result.matched_count == 1 378 | except Exception as e: 379 | print(f"Error updating document: {e}") 380 | return False 381 | 382 | async def get_expired(self, current_time): 383 | expired_users = [] 384 | if data := self.users.find({"expiry_time": {"$lt": current_time}}): 385 | async for user in data: 386 | expired_users.append(user) 387 | return expired_users 388 | 389 | async def remove_premium_access(self, user_id): 390 | return await self.update_one( 391 | {"id": user_id}, {"$set": {"expiry_time": None}} 392 | ) 393 | 394 | async def check_trial_status(self, user_id): 395 | user_data = await self.get_user(user_id) 396 | if user_data: 397 | return user_data.get("has_free_trial", False) 398 | return False 399 | 400 | async def give_free_trial(self, user_id): 401 | user_id = user_id 402 | seconds = 5*60 403 | expiry_time = datetime.now() + timedelta(seconds=seconds) 404 | user_data = {"id": user_id, "expiry_time": expiry_time, "has_free_trial": True} 405 | await self.users.update_one({"id": user_id}, {"$set": user_data}, upsert=True) 406 | 407 | async def give_referal(self, userid): 408 | user_id = userid 409 | seconds = REFERAL_TIME 410 | expiry_time = datetime.now() + timedelta(seconds=seconds) 411 | user_data = {"id": user_id, "expiry_time": expiry_time, "has_free_trial": True} 412 | await self.users.update_one({"id": user_id}, {"$set": user_data}, upsert=True) 413 | 414 | 415 | 416 | db = Database(DATABASE_URI, DATABASE_NAME) 417 | --------------------------------------------------------------------------------