├── Jisshu ├── j ├── bot │ ├── J │ ├── clients.py │ └── __init__.py ├── util │ ├── J │ ├── file_size.py │ ├── human_readable.py │ ├── config_parser.py │ ├── keepalive.py │ ├── time_format.py │ ├── render_template.py │ ├── file_properties.py │ └── custom_dl.py ├── server │ ├── J │ └── exceptions.py ├── template │ ├── J │ ├── req.html │ └── dl.html └── __init__.py ├── .python-version ├── Procfile ├── heroku.yml ├── app.py ├── Dockerfile ├── start.sh ├── plugins ├── b_users.py ├── join_req.py ├── helper │ ├── Channel.py │ ├── telegraph.py │ ├── ban.py │ ├── stream.py │ └── font.py ├── id.py ├── Extra │ ├── Set_update.py │ ├── Link.py │ ├── cmds.py │ ├── Top.py │ ├── Most.py │ ├── ads.py │ ├── Redeem.py │ └── premium.py ├── __init__.py ├── deleteFiles.py ├── banned.py ├── bot_stats.py ├── route.py ├── broadcast.py ├── index.py └── channel.py ├── SECURITY.md ├── logging.conf ├── requirements.txt ├── Template.py ├── database ├── jsreferdb.py ├── topdb.py ├── config_db.py ├── ia_filterdb.py └── users_chats_db.py ├── bot.py ├── README.md ├── info.py ├── utils.py └── Script.py /Jisshu/j: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Jisshu/bot/J: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Jisshu/util/J: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.10.13 -------------------------------------------------------------------------------- /Jisshu/server/J: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Jisshu/template/J: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python bot.py 2 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: Dockerfile 4 | -------------------------------------------------------------------------------- /Jisshu/__init__.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | StartTime = time.time() 4 | __version__ = 1.1 5 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | 6 | @app.route("/") 7 | def hello_world(): 8 | return "https://t.me/JISSHU_BOTS" 9 | -------------------------------------------------------------------------------- /Jisshu/server/exceptions.py: -------------------------------------------------------------------------------- 1 | class InvalidHash(Exception): 2 | message = "Invalid hash" 3 | 4 | 5 | class FIleNotFound(Exception): 6 | message = "File not found" 7 | -------------------------------------------------------------------------------- /Jisshu/util/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 ( 4 | str(bytes) + units[0] 5 | if int(bytes) < 1024 6 | else human_size(int(bytes) >> 10, units[1:]) 7 | ) 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.8-slim-buster 2 | 3 | WORKDIR /Jisshu-filter-bot 4 | RUN chmod 777 /Jisshu-filter-bot 5 | 6 | RUN apt update && apt install -y --no-install-recommends git \ 7 | && rm -rf /var/lib/apt/lists/* 8 | 9 | COPY requirements.txt . 10 | RUN pip install --no-cache-dir -r requirements.txt 11 | 12 | COPY . . 13 | RUN chmod +x start.sh 14 | 15 | CMD ["bash", "start.sh"] 16 | -------------------------------------------------------------------------------- /Jisshu/util/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 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | if [ -z $UPSTREAM_REPO ] 2 | then 3 | echo "Cloning main Repository" 4 | git clone https://github.com/JisshuTG/Jisshu-filter-bot /Jisshu-filter-bot 5 | else 6 | echo "Cloning Custom Repo from $UPSTREAM_REPO " 7 | git clone $UPSTREAM_REPO /Jisshu-filter-bot 8 | fi 9 | cd /Jisshu-filter-bot 10 | pip3 install -U -r requirements.txt 11 | echo "Starting Jisshu filter bot...." 12 | python3 bot.py 13 | -------------------------------------------------------------------------------- /plugins/b_users.py: -------------------------------------------------------------------------------- 1 | from pyrogram.raw.types import UpdateBotStopped 2 | from pyrogram.types import Update 3 | from database.users_chats_db import db 4 | import logging 5 | from pyrogram import Client, ContinuePropagation 6 | 7 | 8 | @Client.on_raw_update(group=-15) 9 | async def blocked_user(_: Client, u: Update, __: dict, ___: dict): 10 | if not isinstance(u, UpdateBotStopped): 11 | raise ContinuePropagation 12 | if not u.stopped: 13 | return 14 | await db.delete_user(u.user_id) 15 | logging.info(f"{u.user_id} - Removed from Database, since blocked account.") 16 | -------------------------------------------------------------------------------- /Jisshu/util/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 | -------------------------------------------------------------------------------- /plugins/join_req.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import ChatJoinRequest 3 | from database.users_chats_db import db 4 | from info import ADMINS, AUTH_CHANNEL 5 | 6 | 7 | @Client.on_chat_join_request(filters.chat(AUTH_CHANNEL)) 8 | async def join_reqs(client, message: ChatJoinRequest): 9 | if not await db.find_join_req(message.from_user.id): 10 | await db.add_join_req(message.from_user.id) 11 | 12 | 13 | @Client.on_message(filters.command("delreq") & filters.private & filters.user(ADMINS)) 14 | async def del_requests(client, message): 15 | await db.del_join_req() 16 | await message.reply("⚙ ꜱᴜᴄᴄᴇꜱꜱғᴜʟʟʏ ᴄʜᴀɴɴᴇʟ ʟᴇғᴛ ᴜꜱᴇʀꜱ ᴅᴇʟᴇᴛᴇᴅ") 17 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /Jisshu/util/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 | -------------------------------------------------------------------------------- /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=('TELEGRAM BOT.LOG','w',) 25 | 26 | [formatter_consoleFormatter] 27 | format=%(asctime)s - %(lineno)d - %(name)s - %(module)s - %(levelname)s - %(message)s 28 | datefmt=%I:%M:%S %p 29 | 30 | [formatter_fileFormatter] 31 | format=[%(asctime)s:%(name)s:%(lineno)d:%(levelname)s] %(message)s 32 | datefmt=%m/%d/%Y %I:%M:%S %p 33 | -------------------------------------------------------------------------------- /plugins/helper/Channel.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters 3 | from pyrogram.types import * 4 | 5 | # Replace this with your own channel ID 6 | CHANNEL_ID = -1001955427962 7 | 8 | 9 | @Client.on_message(filters.channel & filters.media) 10 | async def add_button(client, message): 11 | if message.chat.id == CHANNEL_ID: 12 | button = InlineKeyboardMarkup( 13 | [[InlineKeyboardButton("🔰𝗠𝗼𝘃𝗶𝗲 𝗦𝗲𝗮𝗿𝗰𝗵 𝗚𝗿𝗼𝘂𝗽🔰", url="")]] 14 | ) 15 | 16 | try: 17 | # Try to add the button to the message 18 | await message.edit_reply_markup(reply_markup=button) 19 | await asyncio.sleep(0.5) # Small delay to handle rapid messages 20 | except Exception as e: 21 | print(f"Failed to add button: {e}") 22 | -------------------------------------------------------------------------------- /plugins/id.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters, enums 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.ERROR) 6 | 7 | 8 | @Client.on_message(filters.command("id")) 9 | async def show_id(client, message): 10 | chat_type = message.chat.type 11 | if chat_type == enums.ChatType.PRIVATE: 12 | await message.reply_text( 13 | f"» ᴜꜱᴇʀ ɪᴅ - {message.from_user.id}" 14 | ) 15 | 16 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 17 | await message.reply_text(f"» ɢʀᴏᴜᴘ ɪᴅ - {message.chat.id}") 18 | 19 | elif chat_type == enums.ChatType.CHANNEL: 20 | await message.reply_text( 21 | f"» ᴄʜᴀɴɴᴇʟ ɪᴅ - {message.chat.id}" 22 | ) 23 | -------------------------------------------------------------------------------- /Jisshu/util/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 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrofork==2.3.45 2 | tgcrypto 3 | pymongo[srv]==4.5.0 4 | motor 5 | marshmallow==3.20.1 6 | umongo 7 | git+https://github.com/Joelkb/cinemagoer 8 | search_engine_parser 9 | wget 10 | aiofiles 11 | ffmpeg-python 12 | ffmpeg 13 | requests 14 | aiohttp 15 | ujson 16 | pyshorteners 17 | datetime 18 | pytz 19 | dnspython==2.3.0 20 | python-math 21 | speedtest-cli 22 | shortzy 23 | fuzzywuzzy 24 | wheel 25 | gunicorn==20.1.0 26 | werkzeug==2.0.2 27 | Flask 28 | itsdangerous==2.0.1 29 | python-Levenshtein 30 | 31 | google-search-results 32 | 33 | #jisshu 34 | opencv-python-headless==4.8.1.78 35 | python-dotenv==0.21.1 36 | speedtest==0.0.1 37 | humanize==4.6.0 38 | Pillow==10.3.0 39 | psutil==5.9.4 40 | NumPy 41 | wheel 42 | python-decouple 43 | ffmpeg-python>=0.2.0 44 | 45 | jinja2 46 | apscheduler 47 | pyromod 48 | colorama 49 | 50 | telegraph 51 | 52 | 53 | -------------------------------------------------------------------------------- /plugins/Extra/Set_update.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from info import ADMINS 3 | from database.users_chats_db import db 4 | 5 | 6 | @Client.on_message(filters.command("set_muc") & filters.user(ADMINS)) 7 | async def set_muc_id(client, message): 8 | try: 9 | id = message.command[1] 10 | if id and str(id).startswith("-100") and len(str(id)) == 14: 11 | is_suc = await db.movies_update_channel_id(id) 12 | if is_suc: 13 | await message.reply( 14 | "Successfully set movies update channel id : " + id 15 | ) 16 | else: 17 | await message.reply("Failed to set movies update channel id : " + id) 18 | else: 19 | await message.reply("Invalid channel id : " + id) 20 | except Exception as e: 21 | print("Err in set_muc_id", e) 22 | await message.reply("Failed to set movies channel id! Because : " + str(e)) 23 | -------------------------------------------------------------------------------- /plugins/Extra/Link.py: -------------------------------------------------------------------------------- 1 | # powered by Jisshu_bots and ZISHAN KHAN 2 | from pyrogram import Client, filters 3 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 4 | 5 | 6 | @Client.on_message(filters.command("link")) 7 | async def generate_link(client, message): 8 | command_text = message.text.split(maxsplit=1) 9 | if len(command_text) < 2: 10 | await message.reply( 11 | "Please provide the name for the movie! Example: `/link game of thrones`" 12 | ) 13 | return 14 | movie_name = command_text[1].replace(" ", "-") 15 | link = f"https://telegram.me/NehaTestBot?start=getfile-{movie_name}" 16 | 17 | await message.reply( 18 | text=f"Here is your link: {link}", 19 | reply_markup=InlineKeyboardMarkup( 20 | [ 21 | [ 22 | InlineKeyboardButton( 23 | text="Share Link", 24 | url=f"https://telegram.me/share/url?url={link}", 25 | ) 26 | ] 27 | ] 28 | ), 29 | ) 30 | -------------------------------------------------------------------------------- /Template.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class jisshu_template(object): 4 | JISSHU_NAME = "Jisshu" 5 | 6 | JISSHU_DISCLAIMER = ( 7 | "This website only provides a service to help you play your video online without downloading. " 8 | "You can report files or videos that contain issues like copyright infringement, +18 content, violence, etc." 9 | ) 10 | 11 | JISSHU_REPORT_LINK = "https://t.me/Jisshu_support" 12 | 13 | JISSHU_COLOURS = { 14 | "header": {"background": "#48cffe", "color": "#ffffff"}, 15 | "mx_player": {"background": "#8399ff", "color": "#ffffff"}, 16 | "vlc_player": {"background": "#00e929", "color": "#000000"}, 17 | "playit_player": {"background": "#ff9900", "color": "#000000"}, 18 | "download": {"background": "#00c853", "color": "#ffffff"}, 19 | "create_link": {"background": "#ffd700", "color": "#000000"}, 20 | "share": {"background": "#ff1744", "color": "#ffffff"}, 21 | "file_information": {"background": "#292b2c", "color": "#ffffff"}, 22 | "description": {"background": "#fff2c8", "color": "#6c4c00"}, 23 | } 24 | -------------------------------------------------------------------------------- /database/jsreferdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from info import DATABASE_URI, DATABASE_NAME 3 | import logging 4 | 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.ERROR) 7 | 8 | myclient = pymongo.MongoClient(DATABASE_URI) 9 | mydb = myclient[DATABASE_NAME] 10 | 11 | 12 | class UserTracker: 13 | def __init__(self): 14 | self.user_collection = mydb["referusers"] 15 | self.refer_collection = mydb["refers"] 16 | 17 | def add_user(self, user_id): 18 | if not self.is_user_in_list(user_id): 19 | self.user_collection.insert_one({"user_id": user_id}) 20 | 21 | def remove_user(self, user_id): 22 | self.user_collection.delete_one({"user_id": user_id}) 23 | 24 | def is_user_in_list(self, user_id): 25 | return bool(self.user_collection.find_one({"user_id": user_id})) 26 | 27 | def add_refer_points(self, user_id: int, points: int): 28 | self.refer_collection.update_one( 29 | {"user_id": user_id}, {"$set": {"points": points}}, upsert=True 30 | ) 31 | 32 | def get_refer_points(self, user_id: int): 33 | user = self.refer_collection.find_one({"user_id": user_id}) 34 | return user.get("points") if user else 0 35 | 36 | 37 | referdb = UserTracker() 38 | -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from .route import routes 3 | from asyncio import sleep 4 | from datetime import datetime 5 | from database.users_chats_db import db 6 | from info import LOG_CHANNEL 7 | 8 | 9 | async def web_server(): 10 | web_app = web.Application(client_max_size=30000000) 11 | web_app.add_routes(routes) 12 | return web_app 13 | 14 | 15 | async def check_expired_premium(client): 16 | while 1: 17 | data = await db.get_expired(datetime.now()) 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 | await client.send_message( 24 | chat_id=user_id, 25 | text=f"ʜᴇʏ {user.mention},\n\nʏᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇss ʜᴀs ᴇxᴘɪʀᴇᴅ, ᴛʜᴀɴᴋ ʏᴏᴜ ꜰᴏʀ ᴜsɪɴɢ ᴏᴜʀ sᴇʀᴠɪᴄᴇ 😊\n\nɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ᴛᴀᴋᴇ ᴛʜᴇ ᴘʀᴇᴍɪᴜᴍ ᴀɢᴀɪɴ, ᴛʜᴇɴ ᴄʟɪᴄᴋ ᴏɴ ᴛʜᴇ /plan ꜰᴏʀ ᴛʜᴇ ᴅᴇᴛᴀɪʟs ᴏꜰ ᴛʜᴇ ᴘʟᴀɴs...", 26 | ) 27 | await client.send_message( 28 | LOG_CHANNEL, 29 | text=f"#Premium_Expire\n\nUser name: {user.mention}\nUser id: {user_id}", 30 | ) 31 | except Exception as e: 32 | print(e) 33 | await sleep(0.5) 34 | await sleep(1) 35 | -------------------------------------------------------------------------------- /plugins/helper/telegraph.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from pyrogram import Client, filters 4 | from pyrogram.types import Message 5 | 6 | 7 | @Client.on_message( 8 | filters.command(["img", "cup", "telegraph"], prefixes="/") & filters.reply 9 | ) 10 | async def c_upload(client, message: Message): 11 | reply = message.reply_to_message 12 | 13 | if not reply.media: 14 | return await message.reply_text("Reply to a media to upload it to Cloud.") 15 | 16 | if reply.document and reply.document.file_size > 512 * 1024 * 1024: # 512 MB 17 | return await message.reply_text("File size limit is 512 MB.") 18 | 19 | msg = await message.reply_text("Processing...") 20 | 21 | try: 22 | downloaded_media = await reply.download() 23 | 24 | if not downloaded_media: 25 | return await msg.edit_text("Something went wrong during download.") 26 | 27 | with open(downloaded_media, "rb") as f: 28 | data = f.read() 29 | resp = requests.post("https://envs.sh", files={"file": data}) 30 | if resp.status_code == 200: 31 | await msg.edit_text(f"`{resp.text}`") 32 | else: 33 | await msg.edit_text("Something went wrong. Please try again later.") 34 | 35 | os.remove(downloaded_media) 36 | 37 | except Exception as e: 38 | await msg.edit_text(f"Error: {str(e)}") 39 | -------------------------------------------------------------------------------- /plugins/deleteFiles.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyrogram import Client, filters 3 | from info import DELETE_CHANNELS, LOG_CHANNEL 4 | from database.ia_filterdb import Media, unpack_new_file_id 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | media_filter = filters.document | filters.video | filters.audio 9 | 10 | 11 | @Client.on_message(filters.chat(DELETE_CHANNELS) & media_filter) 12 | async def deletemultiplemedia(bot, message): 13 | media = getattr(message, message.media.value, None) 14 | if media.mime_type in ["video/mp4", "video/x-matroska"]: 15 | file_id, _ = unpack_new_file_id(media.file_id) 16 | try: 17 | result = await Media.find_one({"file_id": file_id}) 18 | if result: 19 | await result.delete() 20 | logger.info( 21 | f"File {media.file_name} with ID {file_id} deleted from database" 22 | ) 23 | else: 24 | logger.warning( 25 | f"File {media.file_name} with ID {file_id} not found in database" 26 | ) 27 | except Exception as e: 28 | logger.error( 29 | f"Error deleting file {media.file_name} with ID {file_id}: {str(e)}" 30 | ) 31 | await bot.send_message( 32 | LOG_CHANNEL, f"Error deleting file {media.file_name}: {str(e)}" 33 | ) 34 | -------------------------------------------------------------------------------- /Jisshu/bot/clients.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from info import * 4 | from pyrogram import Client 5 | from Jisshu.util.config_parser import TokenParser 6 | from . import multi_clients, work_loads, JisshuBot 7 | 8 | 9 | async def initialize_clients(): 10 | multi_clients[0] = JisshuBot 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( 38 | *[start_client(i, token) for i, token in all_tokens.items()] 39 | ) 40 | multi_clients.update(dict(clients)) 41 | if len(multi_clients) != 1: 42 | MULTI_CLIENT = True 43 | print("Multi-Client Mode Enabled") 44 | else: 45 | print("No additional clients were initialized, using default client") 46 | -------------------------------------------------------------------------------- /Jisshu/util/render_template.py: -------------------------------------------------------------------------------- 1 | import jinja2 2 | from info import URL, LOG_CHANNEL 3 | from utils import temp 4 | from Jisshu.bot import JisshuBot 5 | from Jisshu.util.human_readable import humanbytes 6 | from Jisshu.util.file_properties import get_file_ids 7 | from Jisshu.server.exceptions import InvalidHash 8 | from Template import jisshu_template 9 | import urllib.parse 10 | import logging 11 | import aiohttp 12 | 13 | 14 | async def render_page(id, secure_hash, src=None): 15 | file = await JisshuBot.get_messages(int(LOG_CHANNEL), int(id)) 16 | file_data = await get_file_ids(JisshuBot, int(LOG_CHANNEL), int(id)) 17 | if file_data.unique_id[:6] != secure_hash: 18 | logging.debug(f"link hash: {secure_hash} - {file_data.unique_id[:6]}") 19 | logging.debug(f"Invalid hash for message with - ID {id}") 20 | raise InvalidHash 21 | 22 | src = urllib.parse.urljoin( 23 | URL, 24 | f"{id}/{urllib.parse.quote_plus(file_data.file_name)}?hash={secure_hash}", 25 | ) 26 | 27 | tg_button = f"https://telegram.dog/{temp.U_NAME}" 28 | 29 | tag = file_data.mime_type.split("/")[0].strip() 30 | file_size = humanbytes(file_data.file_size) 31 | if tag in ["video", "audio"]: 32 | template_file = "Jisshu/template/req.html" 33 | else: 34 | template_file = "Jisshu/template/dl.html" 35 | async with aiohttp.ClientSession() as s: 36 | async with s.get(src) as u: 37 | file_size = humanbytes(int(u.headers.get("Content-Length"))) 38 | 39 | with open(template_file) as f: 40 | template = jinja2.Template(f.read()) 41 | 42 | file_name = file_data.file_name.replace("_", " ").replace(".", " ") 43 | 44 | return template.render( 45 | file_name=file_name, 46 | file_url=src, 47 | file_size=file_size, 48 | tg_button=tg_button, 49 | file_unique_id=file_data.unique_id, 50 | template_ne=jisshu_template.JISSHU_NAME, 51 | jisshu_disclaimer=jisshu_template.JISSHU_DISCLAIMER, 52 | jisshu_report_link=jisshu_template.JISSHU_REPORT_LINK, 53 | jisshu_colours=jisshu_template.JISSHU_COLOURS, 54 | ) 55 | -------------------------------------------------------------------------------- /Jisshu/util/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 Jisshu.server.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 | 15 | async def parse_file_unique_id(message: "Messages") -> Optional[str]: 16 | media = get_media_from_message(message) 17 | if media: 18 | return media.file_unique_id 19 | 20 | 21 | async def get_file_ids(client: Client, chat_id: int, id: int) -> Optional[FileId]: 22 | message = await client.get_messages(chat_id, id) 23 | if message.empty: 24 | raise FIleNotFound 25 | media = get_media_from_message(message) 26 | file_unique_id = await parse_file_unique_id(message) 27 | file_id = await parse_file_id(message) 28 | setattr(file_id, "file_size", getattr(media, "file_size", 0)) 29 | setattr(file_id, "mime_type", getattr(media, "mime_type", "")) 30 | setattr(file_id, "file_name", getattr(media, "file_name", "")) 31 | setattr(file_id, "unique_id", file_unique_id) 32 | return file_id 33 | 34 | 35 | def get_media_from_message(message: "Message") -> Any: 36 | media_types = ( 37 | "audio", 38 | "document", 39 | "photo", 40 | "sticker", 41 | "animation", 42 | "video", 43 | "voice", 44 | "video_note", 45 | ) 46 | for attr in media_types: 47 | media = getattr(message, attr, None) 48 | if media: 49 | return media 50 | 51 | 52 | def get_hash(media_msg: Message) -> str: 53 | media = get_media_from_message(media_msg) 54 | return getattr(media, "file_unique_id", "")[:6] 55 | 56 | 57 | def get_name(media_msg: Message) -> str: 58 | media = get_media_from_message(media_msg) 59 | return getattr(media, "file_name", "") 60 | 61 | 62 | def get_media_file_size(m): 63 | media = get_media_from_message(m) 64 | return getattr(media, "file_size", 0) 65 | -------------------------------------------------------------------------------- /plugins/banned.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from utils import temp 3 | from pyrogram.types import Message 4 | from database.users_chats_db import db 5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 6 | from info import LOG_CHANNEL 7 | 8 | 9 | async def banned_users(_, client, message: Message): 10 | return ( 11 | message.from_user is not None or not message.sender_chat 12 | ) and message.from_user.id in temp.BANNED_USERS 13 | 14 | 15 | banned_user = filters.create(banned_users) 16 | 17 | 18 | async def disabled_chat(_, client, message: Message): 19 | return message.chat.id in temp.BANNED_CHATS 20 | 21 | 22 | disabled_group = filters.create(disabled_chat) 23 | 24 | 25 | # @Client.on_message(filters.private & banned_user & filters.incoming) 26 | # async def ban_reply(bot, message): 27 | # ban = await db.get_ban_status(message.from_user.id) 28 | # await message.reply(f'Sorry Dude, You are Banned to use Me. \nBan Reason : {ban["ban_reason"]}') 29 | 30 | 31 | @Client.on_message(filters.private & banned_user & filters.incoming) 32 | async def ban_reply(bot, message): 33 | ban = await db.get_ban_status(message.from_user.id) 34 | username = message.from_user.username or "No Username" 35 | # Send reply to the user 36 | await message.reply( 37 | "Telegram says: [400 PEER_ID_INVALID] - The peer id being used is invalid or not known yet. Make sure you meet the peer before interacting with it" 38 | ) 39 | 40 | # Send message to the log channel 41 | await bot.send_message( 42 | LOG_CHANNEL, 43 | f"User ID: {message.from_user.id}\nUsername: @{username} tried to message, but they are banned.\nBan Reason: {ban['ban_reason']}", 44 | ) 45 | 46 | 47 | @Client.on_message(filters.group & disabled_group & filters.incoming) 48 | async def grp_bd(bot, message): 49 | buttons = [[InlineKeyboardButton("Support", url="https://t.me/+BJfqwUjbkQFmNTU1")]] 50 | reply_markup = InlineKeyboardMarkup(buttons) 51 | vazha = await db.get_chat(message.chat.id) 52 | k = await message.reply( 53 | 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']}.", 54 | reply_markup=reply_markup, 55 | ) 56 | try: 57 | await k.pin() 58 | except: 59 | pass 60 | await bot.leave_chat(message.chat.id) 61 | -------------------------------------------------------------------------------- /plugins/Extra/cmds.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters, enums 3 | from pyrogram.types import ( 4 | InlineKeyboardMarkup, 5 | InlineKeyboardButton, 6 | BotCommand, 7 | ) 8 | from utils import is_check_admin 9 | from Script import script 10 | from info import ADMINS, admin_cmds, cmds 11 | 12 | 13 | @Client.on_message(filters.command("grp_cmds")) 14 | async def grp_cmds(client, message): 15 | user_id = message.from_user.id if message.from_user else None 16 | if not user_id: 17 | return await message.reply( 18 | "💔 ʏᴏᴜ ᴀʀᴇ ᴀɴᴏɴʏᴍᴏᴜꜱ ᴀᴅᴍɪɴ ʏᴏᴜ ᴄᴀɴ'ᴛ ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ..." 19 | ) 20 | chat_type = message.chat.type 21 | if chat_type not in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 22 | return await message.reply_text("ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ ɪɴ ɢʀᴏᴜᴘ.") 23 | grp_id = message.chat.id 24 | if not await is_check_admin(client, grp_id, message.from_user.id): 25 | return await message.reply_text("ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴀᴅᴍɪɴ ɪɴ ᴛʜɪꜱ ɢʀᴏᴜᴘ") 26 | # title = message.chat.title 27 | buttons = [[InlineKeyboardButton("❌ ᴄʟᴏsᴇ ❌", callback_data="close_data")]] 28 | await message.reply_text( 29 | text=script.GROUP_C_TEXT, 30 | reply_markup=InlineKeyboardMarkup(buttons), 31 | parse_mode=enums.ParseMode.HTML, 32 | ) 33 | 34 | 35 | @Client.on_message(filters.command("commands") & filters.user(ADMINS)) 36 | async def set_commands(client, message): 37 | commands = [] 38 | for item in cmds: 39 | for command, description in item.items(): 40 | commands.append(BotCommand(command, description)) 41 | await client.set_bot_commands(commands) 42 | await message.reply("Set command successfully✅ ") 43 | 44 | 45 | @Client.on_message(filters.command("admin_cmds") & filters.user(ADMINS)) 46 | async def admin_cmds_handler(client, message): 47 | try: 48 | admin_footer = "\n\nAll These Commands Can Be Used Only By Admins.\n⚡ Powered by @JISSHU_BOTS" 49 | commands_list = "\n".join(f"{i+1}. {cmd}" for i, cmd in enumerate(admin_cmds)) 50 | sent_message = await message.reply( 51 | f"Admin All Commands [auto delete in 2 minutes] 👇\n\n{commands_list}{admin_footer}" 52 | ) 53 | await asyncio.sleep(120) 54 | await sent_message.delete() 55 | await message.delete() 56 | except Exception as e: 57 | print(f"Error in admin_cmds_handler: {e}") 58 | await message.reply("An error occurred while displaying admin commands.") 59 | -------------------------------------------------------------------------------- /database/topdb.py: -------------------------------------------------------------------------------- 1 | from info import DATABASE_URI 2 | import motor.motor_asyncio 3 | import uuid # for generating unique IDs 4 | 5 | 6 | class JsTopDB: 7 | def __init__(self, db_uri): 8 | self.client = motor.motor_asyncio.AsyncIOMotorClient(db_uri) 9 | self.db = self.client["movie_series_db"] 10 | self.collection = self.db["movie_series"] 11 | 12 | async def set_movie_series_names(self, names, group_id): 13 | # Split the input string by comma to get individual names 14 | movie_series_list = names.split(",") 15 | # Store each name in the database for the group with a unique search_id 16 | for name in movie_series_list: 17 | search_id = str(uuid.uuid4()) # Generate unique search_id 18 | await self.collection.update_one( 19 | {"name": name.strip(), "group_id": group_id}, 20 | {"$inc": {"search_count": 1}}, 21 | upsert=True, 22 | ) 23 | 24 | async def get_movie_series_names(self, group_id): 25 | # Retrieve all movie and series names for the specified group from the database 26 | cursor = self.collection.find({"group_id": group_id}) 27 | # Sort by search_count field in descending order 28 | cursor.sort("search_count", -1) 29 | names = [document["name"] async for document in cursor] 30 | return names 31 | 32 | async def clear_movie_series_names(self, group_id): 33 | # Remove all movie and series names for the specified group from the database 34 | await self.collection.delete_many({"group_id": group_id}) 35 | 36 | 37 | async def main(): 38 | movie_series_db = JsTopDB(DATABASE_URI) 39 | while True: 40 | # Simulating a movie search 41 | search_input = input("Enter the movie/series name: ") 42 | group_id = input("Enter group ID: ") 43 | 44 | # Automatically set the movie/series name after search 45 | await movie_series_db.set_movie_series_names(search_input, group_id) 46 | print("Movie/Series name added automatically.") 47 | 48 | # Print the updated list of names after each search 49 | names = await movie_series_db.get_movie_series_names(group_id) 50 | print("Updated Movie/Series Names (Sorted by Search Count):") 51 | for name in names: 52 | print(name) 53 | 54 | # Option to clear names (for testing purposes) 55 | clear_input = input("Do you want to clear names for this group? (yes/no): ") 56 | if clear_input.lower() == "yes": 57 | await movie_series_db.clear_movie_series_names(group_id) 58 | print("Names cleared successfully.") 59 | -------------------------------------------------------------------------------- /plugins/helper/ban.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.errors import PeerIdInvalid 3 | from database.users_chats_db import db 4 | from utils import temp 5 | from info import * 6 | 7 | 8 | @Client.on_message(filters.command("ban") & filters.user(ADMINS)) 9 | async def ban_a_user(bot, message): 10 | # https://t.me/JISSHU_BOTS 11 | if len(message.command) == 1: 12 | return await message.reply("Give me a user id / username") 13 | r = message.text.split(None) 14 | if len(r) > 2: 15 | reason = message.text.split(None, 2)[2] 16 | chat = message.text.split(None, 2)[1] 17 | else: 18 | chat = message.command[1] 19 | reason = "No reason Provided" 20 | try: 21 | chat = int(chat) 22 | except: 23 | pass 24 | try: 25 | k = await bot.get_users(chat) 26 | except PeerIdInvalid: 27 | return await message.reply( 28 | "This is an invalid user, make sure I have met him before." 29 | ) 30 | except IndexError: 31 | return await message.reply("This might be a channel, make sure its a user.") 32 | except Exception as e: 33 | return await message.reply(f"Error - {e}") 34 | else: 35 | jar = await db.get_ban_status(k.id) 36 | if jar["is_banned"]: 37 | return await message.reply( 38 | f"{k.mention} is already banned\nReason: {jar['ban_reason']}" 39 | ) 40 | await db.ban_user(k.id, reason) 41 | temp.BANNED_USERS.append(k.id) 42 | await message.reply(f"Successfully banned {k.mention}") 43 | 44 | 45 | @Client.on_message(filters.command("unban") & filters.user(ADMINS)) 46 | async def unban_a_user(bot, message): 47 | if len(message.command) == 1: 48 | return await message.reply("Give me a user id / username") 49 | r = message.text.split(None) 50 | if len(r) > 2: 51 | reason = message.text.split(None, 2)[2] 52 | chat = message.text.split(None, 2)[1] 53 | else: 54 | chat = message.command[1] 55 | reason = "No reason Provided" 56 | try: 57 | chat = int(chat) 58 | except: 59 | pass 60 | try: 61 | k = await bot.get_users(chat) 62 | except PeerIdInvalid: 63 | return await message.reply( 64 | "This is an invalid user, make sure ia have met him before." 65 | ) 66 | except IndexError: 67 | return await message.reply("Thismight be a channel, make sure its a user.") 68 | except Exception as e: 69 | return await message.reply(f"Error - {e}") 70 | else: 71 | jar = await db.get_ban_status(k.id) 72 | if not jar["is_banned"]: 73 | return await message.reply(f"{k.mention} is not yet banned.") 74 | await db.remove_ban(k.id) 75 | temp.BANNED_USERS.remove(k.id) 76 | await message.reply(f"Successfully unbanned {k.mention}") 77 | -------------------------------------------------------------------------------- /plugins/Extra/Top.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from info import ADMINS, DATABASE_URI 3 | from pyrogram.types import ReplyKeyboardMarkup 4 | from database.topdb import JsTopDB 5 | 6 | movie_series_db = JsTopDB(DATABASE_URI) 7 | 8 | 9 | # top trending commands 10 | @Client.on_message(filters.command("setlist") & filters.private & filters.user(ADMINS)) 11 | async def set_movie_series_names_command(client, message): 12 | 13 | try: 14 | command, *names = message.text.split(maxsplit=1) 15 | except ValueError: 16 | await message.reply( 17 | "Pʟᴇᴀsᴇ ᴘʀᴏᴠɪᴅᴇ ᴀ ʟɪsᴛ ᴏғ ᴍᴏᴠɪᴇ ᴀɴᴅ sᴇʀɪᴇs ɴᴀᴍᴇs ᴀғᴛᴇʀ ᴛʜᴇ ᴄᴏᴍᴍᴀɴᴅ." 18 | ) 19 | return 20 | 21 | if not names: 22 | await message.reply( 23 | "Pʟᴇᴀsᴇ ᴘʀᴏᴠɪᴅᴇ ᴀ ʟɪsᴛ ᴏғ ᴍᴏᴠɪᴇ ᴀɴᴅ sᴇʀɪᴇs ɴᴀᴍᴇs ᴀғᴛᴇʀ ᴛʜᴇ ᴄᴏᴍᴍᴀɴᴅ." 24 | ) 25 | return 26 | 27 | names_string = " ".join(names) 28 | 29 | capitalized_names = ", ".join( 30 | " ".join(word.capitalize() for word in name.split()) 31 | for name in names_string.split(",") 32 | ) 33 | 34 | await movie_series_db.set_movie_series_names(capitalized_names, 1) 35 | 36 | await message.reply( 37 | "Tʜᴇ ʟɪsᴛ ᴏғ ᴍᴏᴠɪᴇ ᴀɴᴅ sᴇʀɪᴇs ɴᴀᴍᴇs ғᴏʀ ᴛʜᴇ sᴜɢɢᴇsᴛɪᴏɴ ʜᴀs ʙᴇᴇɴ ᴜᴘᴅᴀᴛᴇᴅ sᴜᴄᴄᴇssғᴜʟʟʏ ✅" 38 | ) 39 | 40 | 41 | @Client.on_message(filters.command("trendlist")) 42 | async def get_movie_series_names_command(client, message): 43 | current_names = await movie_series_db.get_movie_series_names(1) 44 | 45 | if current_names: 46 | response = "Cᴜʀʀᴇɴᴛ ʟɪsᴛ ᴏғ ᴛᴏᴘ ᴛʀᴇɴᴅɪɴɢ:\n" 47 | for i, name in enumerate(current_names, start=1): 48 | response += f"{i}. {name}\n" 49 | await message.reply(response.strip()) 50 | else: 51 | await message.reply("Tʜᴇ ʟɪsᴛ ᴏғ ᴛᴏᴘ ᴛʀᴇɴᴅɪɴɢ ғᴏʀ ʙᴜᴛᴛᴏɴs ᴀʀᴇ ᴇᴍᴘᴛʏ ❌") 52 | 53 | 54 | @Client.on_message( 55 | filters.command("clearlist") & filters.private & filters.user(ADMINS) 56 | ) 57 | async def clear_movie_series_names_command(client, message): 58 | await movie_series_db.clear_movie_series_names(1) 59 | await message.reply("Tʜᴇ ᴛᴏᴘ ᴛʀᴇɴᴅɪɴɢ ʟɪsᴛ ʜᴀs ʙᴇᴇɴ ᴄʟᴇᴀʀᴇᴅ sᴜᴄᴄᴇssғᴜʟʟʏ ✅") 60 | 61 | 62 | @Client.on_message(filters.command("trend")) 63 | async def trending_command(client, message): 64 | 65 | movie_series_names = await movie_series_db.get_movie_series_names(1) 66 | 67 | if not movie_series_names: 68 | await message.reply( 69 | "Tʜᴇʀᴇ ᴀʀᴇ ɴᴏ ᴍᴏᴠɪᴇ ᴏʀ sᴇʀɪᴇs ɴᴀᴍᴇs ᴀᴠᴀɪʟᴀʙʟᴇ ғᴏʀ ᴛʜᴇ ᴛᴏᴘ sᴇᴀʀᴄʜᴇs." 70 | ) 71 | return 72 | 73 | buttons = [ 74 | movie_series_names[i : i + 2] for i in range(0, len(movie_series_names), 2) 75 | ] 76 | 77 | spika = ReplyKeyboardMarkup(buttons, resize_keyboard=True) 78 | m = await message.reply_text("𝐏𝐥𝐞𝐚𝐬𝐞 𝐖𝐚𝐢𝐭, 𝐅𝐞𝐭𝐜𝐡𝐢𝐧𝐠 𝐓𝐨𝐩 𝐓𝐫𝐞𝐧𝐝𝐢𝐧𝐠...") 79 | await m.delete() 80 | await message.reply("Hᴇʀᴇ ɪꜱ ᴛʜᴇ ᴛᴏᴘ ᴛʀᴇɴᴅɪɴɢ ʟɪꜱᴛ 👇", reply_markup=spika) 81 | -------------------------------------------------------------------------------- /plugins/helper/stream.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters, enums 2 | from pyrogram.types import ( 3 | InlineKeyboardButton, 4 | InlineKeyboardMarkup, 5 | ) 6 | from info import URL, LOG_CHANNEL 7 | from urllib.parse import quote_plus 8 | from Jisshu.util.file_properties import get_name, get_hash, get_media_file_size 9 | from Jisshu.util.human_readable import humanbytes 10 | import humanize 11 | 12 | 13 | @Client.on_message(filters.private & filters.command("streams")) 14 | async def stream_start(client, message): 15 | msg = await client.ask( 16 | message.chat.id, 17 | "**Now send me your file/video to get stream and download link**", 18 | ) 19 | if not msg.media: 20 | return await message.reply("**Please send me supported media.**") 21 | if msg.media in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.DOCUMENT]: 22 | file = getattr(msg, msg.media.value) 23 | filename = file.file_name 24 | filesize = humanize.naturalsize(file.file_size) 25 | fileid = file.file_id 26 | user_id = message.from_user.id 27 | username = message.from_user.mention 28 | 29 | log_msg = await client.send_cached_media( 30 | chat_id=LOG_CHANNEL, 31 | file_id=fileid, 32 | ) 33 | fileName = {quote_plus(get_name(log_msg))} 34 | stream = f"{URL}watch/{str(log_msg.id)}?hash={get_hash(log_msg)}" 35 | download = f"{URL}{str(log_msg.id)}?hash={get_hash(log_msg)}" 36 | 37 | await log_msg.reply_text( 38 | text=f"•• ʟɪɴᴋ ɢᴇɴᴇʀᴀᴛᴇᴅ ꜰᴏʀ ɪᴅ #{user_id} \n•• ᴜꜱᴇʀɴᴀᴍᴇ : {username} \n\n•• ᖴᎥᒪᗴ Nᗩᗰᗴ : {fileName}", 39 | quote=True, 40 | disable_web_page_preview=True, 41 | reply_markup=InlineKeyboardMarkup( 42 | [ 43 | [ 44 | InlineKeyboardButton( 45 | "🚀 Fast Download 🚀", url=download 46 | ), # we download Link 47 | InlineKeyboardButton("🖥️ Watch online 🖥️", url=stream), 48 | ] 49 | ] 50 | ), # web stream Link 51 | ) 52 | rm = InlineKeyboardMarkup( 53 | [ 54 | [ 55 | InlineKeyboardButton("sᴛʀᴇᴀᴍ 🖥", url=stream), 56 | InlineKeyboardButton("ᴅᴏᴡɴʟᴏᴀᴅ 📥", url=download), 57 | ] 58 | ] 59 | ) 60 | msg_text = """𝗬𝗼𝘂𝗿 𝗟𝗶𝗻𝗸 𝗚𝗲𝗻𝗲𝗿𝗮𝘁𝗲𝗱 !\n\n📂 Fɪʟᴇ ɴᴀᴍᴇ : {}\n\n📦 Fɪʟᴇ ꜱɪᴢᴇ : {}\n\n📥 Dᴏᴡɴʟᴏᴀᴅ : {}\n\n 🖥ᴡᴀᴛᴄʜ : {}\n\n🚸 Nᴏᴛᴇ : ʟɪɴᴋ ᴡᴏɴ'ᴛ ᴇxᴘɪʀᴇ ᴛɪʟʟ ɪ ᴅᴇʟᴇᴛᴇ""" 61 | 62 | await message.reply_text( 63 | text=msg_text.format( 64 | get_name(log_msg), 65 | humanbytes(get_media_file_size(msg)), 66 | download, 67 | stream, 68 | ), 69 | quote=True, 70 | disable_web_page_preview=True, 71 | reply_markup=rm, 72 | ) 73 | -------------------------------------------------------------------------------- /Jisshu/bot/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | 4 | logging.config.fileConfig("logging.conf") 5 | logging.getLogger().setLevel(logging.INFO) 6 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 7 | logging.getLogger("imdbpy").setLevel(logging.ERROR) 8 | logging.basicConfig( 9 | level=logging.INFO, 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 info import * 23 | 24 | 25 | class JisshuxBot(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 | 38 | async def iter_messages( 39 | self, 40 | chat_id: Union[int, str], 41 | limit: int, 42 | offset: int = 0, 43 | ) -> Optional[AsyncGenerator["types.Message", None]]: 44 | """Iterate through a chat sequentially. 45 | This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_messages` in a loop, thus saving 46 | you from the hassle of setting up boilerplate code. It is useful for getting the whole chat messages with a 47 | single call. 48 | Parameters: 49 | chat_id (``int`` | ``str``): 50 | Unique identifier (int) or username (str) of the target chat. 51 | For your personal cloud (Saved Messages) you can simply use "me" or "self". 52 | For a contact that exists in your Telegram address book you can use his phone number (str). 53 | 54 | limit (``int``): 55 | Identifier of the last message to be returned. 56 | 57 | offset (``int``, *optional*): 58 | Identifier of the first message to be returned. 59 | Defaults to 0. 60 | Returns: 61 | ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. 62 | Example: 63 | .. code-block:: python 64 | for message in app.iter_messages("pyrogram", 1, 15000): 65 | print(message.text) 66 | """ 67 | current = offset 68 | while True: 69 | new_diff = min(200, limit - current) 70 | if new_diff <= 0: 71 | return 72 | messages = await self.get_messages( 73 | chat_id, list(range(current, current + new_diff + 1)) 74 | ) 75 | for message in messages: 76 | yield message 77 | current += 1 78 | 79 | 80 | JisshuBot = JisshuxBot() 81 | 82 | multi_clients = {} 83 | work_loads = {} 84 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import glob 3 | import importlib 4 | from pathlib import Path 5 | from pyrogram import idle 6 | import logging 7 | import logging.config 8 | 9 | # Get logging configurations 10 | logging.config.fileConfig("logging.conf") 11 | logging.getLogger().setLevel(logging.INFO) 12 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 13 | logging.getLogger("imdbpy").setLevel(logging.ERROR) 14 | logging.basicConfig( 15 | level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" 16 | ) 17 | logging.getLogger("aiohttp").setLevel(logging.ERROR) 18 | logging.getLogger("aiohttp.web").setLevel(logging.ERROR) 19 | 20 | 21 | from pyrogram import __version__ 22 | from pyrogram.raw.all import layer 23 | from database.ia_filterdb import Media 24 | from database.users_chats_db import db 25 | from info import * 26 | from utils import temp 27 | from Script import script 28 | from datetime import date, datetime 29 | import pytz 30 | from aiohttp import web 31 | from plugins import web_server, check_expired_premium 32 | import pyrogram.utils 33 | import asyncio 34 | from Jisshu.bot import JisshuBot 35 | from Jisshu.util.keepalive import ping_server 36 | from Jisshu.bot.clients import initialize_clients 37 | 38 | ppath = "plugins/*.py" 39 | files = glob.glob(ppath) 40 | JisshuBot.start() 41 | loop = asyncio.get_event_loop() 42 | 43 | pyrogram.utils.MIN_CHANNEL_ID = -1009147483647 44 | 45 | 46 | async def Jisshu_start(): 47 | print("\n") 48 | print("Credit - Telegram @JISSHU_BOTS") 49 | bot_info = await JisshuBot.get_me() 50 | JisshuBot.username = bot_info.username 51 | await initialize_clients() 52 | for name in files: 53 | with open(name) as a: 54 | patt = Path(a.name) 55 | plugin_name = patt.stem.replace(".py", "") 56 | plugins_dir = Path(f"plugins/{plugin_name}.py") 57 | import_path = "plugins.{}".format(plugin_name) 58 | spec = importlib.util.spec_from_file_location(import_path, plugins_dir) 59 | load = importlib.util.module_from_spec(spec) 60 | spec.loader.exec_module(load) 61 | sys.modules["plugins." + plugin_name] = load 62 | print("JisshuBot Imported => " + plugin_name) 63 | if ON_HEROKU: 64 | asyncio.create_task(ping_server()) 65 | b_users, b_chats = await db.get_banned() 66 | temp.BANNED_USERS = b_users 67 | temp.BANNED_CHATS = b_chats 68 | await Media.ensure_indexes() 69 | me = await JisshuBot.get_me() 70 | temp.ME = me.id 71 | temp.U_NAME = me.username 72 | temp.B_NAME = me.first_name 73 | temp.B_LINK = me.mention 74 | JisshuBot.username = "@" + me.username 75 | JisshuBot.loop.create_task(check_expired_premium(JisshuBot)) 76 | logging.info( 77 | f"{me.first_name} with for Pyrogram v{__version__} (Layer {layer}) started on {me.username}." 78 | ) 79 | logging.info(script.LOGO) 80 | tz = pytz.timezone("Asia/Kolkata") 81 | today = date.today() 82 | now = datetime.now(tz) 83 | time = now.strftime("%H:%M:%S %p") 84 | await JisshuBot.send_message( 85 | chat_id=LOG_CHANNEL, text=script.RESTART_TXT.format(me.mention, today, time) 86 | ) 87 | await JisshuBot.send_message( 88 | chat_id=SUPPORT_GROUP, text=f"{me.mention} ʀᴇsᴛᴀʀᴛᴇᴅ 🤖" 89 | ) 90 | app = web.AppRunner(await web_server()) 91 | await app.setup() 92 | bind_address = "0.0.0.0" 93 | await web.TCPSite(app, bind_address, PORT).start() 94 | await idle() 95 | 96 | 97 | if __name__ == "__main__": 98 | try: 99 | loop.run_until_complete(Jisshu_start()) 100 | except KeyboardInterrupt: 101 | logging.info("Service Stopped Bye 👋") 102 | -------------------------------------------------------------------------------- /plugins/Extra/Most.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pyrogram import Client, filters 3 | from pyrogram.types import ReplyKeyboardMarkup 4 | from database.config_db import mdb 5 | 6 | 7 | # most search commands 8 | @Client.on_message(filters.command("most")) 9 | async def most(client, message): 10 | 11 | def is_alphanumeric(string): 12 | return bool(re.match("^[a-zA-Z0-9 ]*$", string)) 13 | 14 | try: 15 | limit = int(message.command[1]) 16 | except (IndexError, ValueError): 17 | limit = 20 18 | 19 | top_messages = await mdb.get_top_messages(limit) 20 | 21 | # Use a set to ensure unique messages (case sensitive). 22 | seen_messages = set() 23 | truncated_messages = [] 24 | 25 | for msg in top_messages: 26 | # Check if message already exists in the set (case sensitive) 27 | if msg.lower() not in seen_messages and is_alphanumeric(msg): 28 | seen_messages.add(msg.lower()) 29 | 30 | if len(msg) > 35: 31 | truncated_messages.append(msg[: 35 - 3]) 32 | else: 33 | truncated_messages.append(msg) 34 | 35 | keyboard = [] 36 | for i in range(0, len(truncated_messages), 2): 37 | row = truncated_messages[i : i + 2] 38 | keyboard.append(row) 39 | 40 | reply_markup = ReplyKeyboardMarkup( 41 | keyboard, 42 | one_time_keyboard=True, 43 | resize_keyboard=True, 44 | placeholder="Most searches of the day", 45 | ) 46 | m = await message.reply_text("𝑃𝑙𝑒𝑎𝑠𝑒 𝑊𝑎𝑖𝑡, 𝐹𝑒𝑡𝑐ℎ𝑖𝑛𝑔 𝑀𝑜𝑠𝑡 𝑆𝑒𝑎𝑟𝑐ℎ𝑒𝑠.") 47 | await m.edit_text("𝑃𝑙𝑒𝑎𝑠𝑒 𝑊𝑎𝑖𝑡, 𝐹𝑒𝑡𝑐ℎ𝑖𝑛𝑔 𝑀𝑜𝑠𝑡 𝑆𝑒𝑎𝑟𝑐ℎ𝑒𝑠..") 48 | await m.delete() 49 | await message.reply_text( 50 | "Hᴇʀᴇ ɪꜱ ᴛʜᴇ ᴍᴏꜱᴛ ꜱᴇᴀʀᴄʜᴇꜱ ʟɪꜱᴛ 👇", reply_markup=reply_markup 51 | ) 52 | 53 | 54 | @Client.on_message(filters.command("mostlist")) 55 | async def trendlist(client, message): 56 | def is_alphanumeric(string): 57 | return bool(re.match("^[a-zA-Z0-9 ]*$", string)) 58 | 59 | # Set the limit to the default if no argument is provided 60 | limit = 31 61 | 62 | # Check if an argument is provided and if it's a valid number 63 | if len(message.command) > 1: 64 | try: 65 | limit = int(message.command[1]) 66 | except ValueError: 67 | await message.reply_text( 68 | "Invalid number format.\nPlease provide a valid number after the /trendlist command." 69 | ) 70 | return # Exit the function if the argument is not a valid integer 71 | 72 | try: 73 | top_messages = await mdb.get_top_messages(limit) 74 | except Exception as e: 75 | await message.reply_text(f"Error retrieving messages: {str(e)}") 76 | return # Exit the function if there is an error retrieving messages 77 | 78 | if not top_messages: 79 | await message.reply_text("No most messages found.") 80 | return # Exit the function if no messages are found 81 | 82 | seen_messages = set() 83 | truncated_messages = [] 84 | 85 | for msg in top_messages: 86 | if msg.lower() not in seen_messages and is_alphanumeric(msg): 87 | seen_messages.add(msg.lower()) 88 | 89 | # Add an ellipsis to indicate the message has been truncated 90 | truncated_messages.append(msg[:32] + "..." if len(msg) > 35 else msg) 91 | 92 | if not truncated_messages: 93 | await message.reply_text("No valid most messages found.") 94 | return # Exit the function if no valid messages are found 95 | 96 | # Create a formatted text list 97 | formatted_list = "\n".join( 98 | [f"{i+1}. {msg}" for i, msg in enumerate(truncated_messages)] 99 | ) 100 | 101 | # Append the additional message at the end 102 | additional_message = "𝑨𝒍𝒍 𝒕𝒉𝒆 𝒓𝒆𝒔𝒖𝒍𝒕𝒔 𝒂𝒃𝒐𝒗𝒆 𝒄𝒐𝒎𝒆 𝒇𝒓𝒐𝒎 𝒘𝒉𝒂𝒕 𝒖𝒔𝒆𝒓𝒔 𝒉𝒂𝒗𝒆 𝒔𝒆𝒂𝒓𝒄𝒉𝒆𝒅 𝒇𝒐𝒓. 𝑻𝒉𝒆𝒚'𝒓𝒆 𝒔𝒉𝒐𝒘𝒏 𝒕𝒐 𝒚𝒐𝒖 𝒆𝒙𝒂𝒄𝒕𝒍𝒚 𝒂𝒔 𝒕𝒉𝒆𝒚 𝒘𝒆𝒓𝒆 𝒔𝒆𝒂𝒓𝒄𝒉𝒆𝒅, 𝒘𝒊𝒕𝒉𝒐𝒖𝒕 𝒂𝒏𝒚 𝒄𝒉𝒂𝒏𝒈𝒆𝒔 𝒃𝒚 𝒕𝒉𝒆 𝒐𝒘𝒏𝒆𝒓." 103 | formatted_list += f"\n\n{additional_message}" 104 | 105 | reply_text = f"Top {len(truncated_messages)} Most Searches List:\n\n{formatted_list}" 106 | 107 | await message.reply_text(reply_text) 108 | -------------------------------------------------------------------------------- /plugins/Extra/ads.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from datetime import datetime, timedelta 3 | from database.config_db import mdb 4 | from database.users_chats_db import db 5 | from info import ADMINS 6 | import asyncio 7 | import re 8 | 9 | 10 | @Client.on_message(filters.private & filters.command("set_ads") & filters.user(ADMINS)) 11 | async def set_ads(client, message): 12 | try: 13 | command_args = message.text.split(maxsplit=1)[1] 14 | if "#" not in command_args or len(command_args.split("#")) < 3: 15 | await message.reply_text( 16 | "Usage: /set_ads {ads name}#{time}#{photo URL} Explain" 17 | ) 18 | return 19 | 20 | ads_name, duration_or_impression, url = command_args.split("#", 2) 21 | ads_name = ads_name.strip() 22 | url = url.strip() 23 | 24 | if len(ads_name) > 35: 25 | await message.reply_text( 26 | "Advertisement name should not exceed 35 characters." 27 | ) 28 | return 29 | 30 | if not re.match(r"https?://.+", url): 31 | await message.reply_text("Invalid URL format. Use a valid Telegram link.") 32 | return 33 | 34 | expiry_date = None 35 | impression_count = None 36 | 37 | if duration_or_impression[0] == "d": 38 | 39 | duration = duration_or_impression[1:] 40 | if not duration.isdigit(): 41 | await message.reply_text("Duration must be a number.") 42 | return 43 | expiry_date = datetime.now() + timedelta(days=int(duration)) 44 | elif duration_or_impression[0] == "i": 45 | 46 | impression = duration_or_impression[1:] 47 | if not impression.isdigit(): 48 | await message.reply_text("Impression count must be a number.") 49 | return 50 | impression_count = int(impression) 51 | else: 52 | await message.reply_text( 53 | "Invalid prefix. Use 'd' for duration and 'i' for impression count." 54 | ) 55 | return 56 | 57 | reply = message.reply_to_message 58 | if not reply: 59 | await message.reply_text( 60 | "Reply to a message to set it as your advertisement." 61 | ) 62 | return 63 | if not reply.text: 64 | await message.reply_text("Only text messages are supported.") 65 | return 66 | 67 | await mdb.update_advirtisment( 68 | reply.text, f"{ads_name}", expiry_date, impression_count 69 | ) 70 | await db.jisshu_set_ads_link(url) 71 | 72 | await asyncio.sleep(3) 73 | _, name, _ = await mdb.get_advirtisment() 74 | await message.reply_text( 75 | f"Advertisement: '{name}' has been set with the stream link: {url}" 76 | ) 77 | except Exception as e: 78 | await message.reply_text(f"An error occurred: {str(e)}") 79 | 80 | 81 | @Client.on_message(filters.private & filters.command("ads")) 82 | async def ads(_, message): 83 | try: 84 | _, name, impression = await mdb.get_advirtisment() 85 | if not name: 86 | await message.reply_text("No ads set.") 87 | return 88 | if impression == 0: 89 | await message.reply_text(f"Advertisement: '{name}' has expired.") 90 | return 91 | await message.reply_text( 92 | f"Advertisement: '{name}' has {impression} impressions left." 93 | ) 94 | except Exception as e: 95 | await message.reply_text(f"An error occurred: {str(e)}") 96 | 97 | 98 | def checkIfLinkIsValid(link): 99 | if re.match(r"^https?://(?:www\.)?\S+$", link): 100 | return True 101 | else: 102 | return False 103 | 104 | 105 | @Client.on_message(filters.private & filters.command("del_ads") & filters.user(ADMINS)) 106 | async def del_ads(client, message): 107 | try: 108 | await mdb.update_advirtisment() 109 | 110 | current_link = await db.jisshu_get_ads_link() 111 | if current_link: 112 | is_deleted = await db.jisshu_del_ads_link() 113 | if is_deleted: 114 | await message.reply( 115 | f"Successfully deleted advertisement and ads photo link: {current_link}!" 116 | ) 117 | else: 118 | await message.reply( 119 | "Advertisement reset, but stream link deletion failed. Stream link not found or something went wrong! Check logs" 120 | ) 121 | else: 122 | await message.reply("Advertisement reset. ads photo link not found!") 123 | except Exception as e: 124 | await message.reply(f"An error occurred: {str(e)}") 125 | -------------------------------------------------------------------------------- /database/config_db.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | from info import DATABASE_URI 3 | from datetime import datetime 4 | 5 | 6 | class Database: 7 | def __init__(self, uri, db_name): 8 | self.client = AsyncIOMotorClient(uri) 9 | self.db = self.client[db_name] 10 | self.col = self.db.user 11 | self.config_col = self.db.configuration 12 | 13 | async def update_top_messages(self, user_id, message_text): 14 | user = await self.col.find_one( 15 | {"user_id": user_id, "messages.text": message_text} 16 | ) 17 | 18 | if not user: 19 | await self.col.update_one( 20 | {"user_id": user_id}, 21 | {"$push": {"messages": {"text": message_text, "count": 1}}}, 22 | upsert=True, 23 | ) 24 | else: 25 | await self.col.update_one( 26 | {"user_id": user_id, "messages.text": message_text}, 27 | {"$inc": {"messages.$.count": 1}}, 28 | ) 29 | 30 | async def get_top_messages(self, limit=30): 31 | pipeline = [ 32 | {"$unwind": "$messages"}, 33 | {"$group": {"_id": "$messages.text", "count": {"$sum": "$messages.count"}}}, 34 | {"$sort": {"count": -1}}, 35 | {"$limit": limit}, 36 | ] 37 | results = await self.col.aggregate(pipeline).to_list(limit) 38 | return [result["_id"] for result in results] 39 | 40 | async def delete_all_messages(self): 41 | await self.col.delete_many({}) 42 | 43 | def create_configuration_data(self, advertisement=None): 44 | 45 | return { 46 | "advertisement": advertisement, 47 | } 48 | 49 | async def update_advirtisment( 50 | self, ads_string=None, ads_name=None, expiry=None, impression=None 51 | ): 52 | config = await self.config_col.find_one({}) 53 | if not config: 54 | await self.config_col.insert_one(self.create_configuration_data()) 55 | config = await self.config_col.find_one({}) 56 | 57 | advertisement = config.get("advertisement") 58 | 59 | if advertisement is None: 60 | # If 'advertisement' field is not present, create it 61 | advertisement = {} 62 | config["advertisement"] = advertisement 63 | 64 | # Update the fields within the 'advertisement' field 65 | advertisement["ads_string"] = ads_string 66 | advertisement["ads_name"] = ads_name 67 | advertisement["expiry"] = expiry 68 | advertisement["impression_count"] = impression 69 | 70 | await self.config_col.update_one( 71 | {}, {"$set": {"advertisement": advertisement}}, upsert=True 72 | ) 73 | 74 | async def update_advirtisment_impression(self, impression=None): 75 | await self.config_col.update_one( 76 | {}, {"$set": {"advertisement.impression_count": impression}}, upsert=True 77 | ) 78 | 79 | async def get_advirtisment(self): 80 | configuration = await self.config_col.find_one({}) 81 | if not configuration: 82 | await self.config_col.insert_one(self.create_configuration_data()) 83 | configuration = await self.config_col.find_one({}) 84 | advertisement = configuration.get("advertisement", False) 85 | if advertisement: 86 | return ( 87 | advertisement.get("ads_string"), 88 | advertisement.get("ads_name"), 89 | advertisement.get("impression_count"), 90 | ) 91 | return None, None, None 92 | 93 | async def reset_advertisement_if_expired(self): 94 | configuration = await self.config_col.find_one({}) 95 | if configuration: 96 | advertisement = configuration.get("advertisement", False) 97 | if advertisement: 98 | impression_count = advertisement.get("impression_count", 0) 99 | expiry = advertisement.get("expiry", None) 100 | if (impression_count == 0) or (expiry and datetime.now() > expiry): 101 | await self.config_col.update_one( 102 | {}, {"$set": {"advertisement": None}} 103 | ) 104 | 105 | async def update_configuration(self, key, value): 106 | try: 107 | await self.config_col.update_one({}, {"$set": {key: value}}, upsert=True) 108 | 109 | except Exception as e: 110 | print(f"An error occurred: {e}") 111 | 112 | async def get_configuration_value(self, key): 113 | configuration = await self.config_col.find_one({}) 114 | if not configuration: 115 | await self.config_col.insert_one(self.create_configuration_data()) 116 | configuration = await self.config_col.find_one({}) 117 | return configuration.get(key, False) 118 | 119 | 120 | mdb = Database(DATABASE_URI, "admin_database") 121 | -------------------------------------------------------------------------------- /Jisshu/template/req.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{file_name}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 |
23 |

{{template_ne}}

24 | 27 |
28 |
29 | 30 | 31 |
32 |
33 | 36 | 37 |
38 | 39 | 50 | 51 |
52 | 57 |
58 | 59 | 60 | Create Like This Link 61 | 62 | 63 | 64 | Share Now 65 | 66 | 67 |
68 |
69 |
File Information
70 |
71 |
72 |
73 |
74 |

Name: {{file_name}}

75 |

Size: {{file_size}}

76 |
77 |
78 |
79 |
80 | 81 |
82 |
Disclaimer
83 |

{{jisshu_disclaimer}}

84 |
85 | Report 86 |
87 |
88 |
89 | 90 | 91 | 92 | 93 | 94 | 95 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /plugins/Extra/Redeem.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta, datetime 2 | import pytz 3 | from pyrogram import Client, filters 4 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 5 | from info import ADMINS, LOG_CHANNEL 6 | from utils import get_seconds 7 | from database.users_chats_db import db 8 | import string 9 | import random 10 | 11 | VALID_REDEEM_CODES = {} 12 | 13 | 14 | def generate_code(length=8): 15 | letters_and_digits = string.ascii_letters + string.digits 16 | return "".join(random.choice(letters_and_digits) for _ in range(length)) 17 | 18 | 19 | @Client.on_message(filters.command("add_redeem") & filters.user(ADMINS)) 20 | async def add_redeem_code(client, message): 21 | user_id = message.from_user.id 22 | if len(message.command) == 3: 23 | try: 24 | time = message.command[1] 25 | num_codes = int(message.command[2]) 26 | except ValueError: 27 | await message.reply_text( 28 | "Please provide a valid number of codes to generate." 29 | ) 30 | return 31 | 32 | codes = [] 33 | for _ in range(num_codes): 34 | code = generate_code() 35 | VALID_REDEEM_CODES[code] = time 36 | codes.append(code) 37 | 38 | codes_text = "\n".join(f"➔ /redeem {code}" for code in codes) 39 | response_text = f""" 40 | Gɪғᴛᴄᴏᴅᴇ Gᴇɴᴇʀᴀᴛᴇᴅ ✅ 41 | Aᴍᴏᴜɴᴛ: {num_codes} 42 | 43 | {codes_text} 44 | Duration: {time} 45 | 46 | 🔰𝗥𝗲𝗱𝗲𝗲𝗺 𝗜𝗻𝘀𝘁𝗿𝘂𝗰𝘁𝗶𝗼𝗻🔰 47 | 𝙹𝚞𝚜𝚝 𝚌𝚕𝚒𝚌𝚔 𝚝𝚑𝚎 𝚊𝚋𝚘𝚟𝚎 𝚌𝚘𝚍𝚎 𝚝𝚘 𝚌𝚘𝚙𝚢 𝚊𝚗𝚍 𝚝𝚑𝚎𝚗 𝚜𝚎𝚗𝚍 𝚝𝚑𝚊𝚝 𝚌𝚘𝚍𝚎 𝚝𝚘 𝚝𝚑𝚎 𝙱𝚘𝚝, 𝚝𝚑𝚊𝚝'𝚜 𝚒𝚝 🔥""" 48 | 49 | keyboard = InlineKeyboardMarkup( 50 | [ 51 | [ 52 | InlineKeyboardButton( 53 | "♻️ Redeem Here ♻️", url="http://t.me/NehaTestBot" 54 | ) 55 | ], 56 | [InlineKeyboardButton("❕ Any Query ❕", url="https://t.me/IM_JISSHU")], 57 | ] 58 | ) 59 | 60 | await message.reply_text(response_text, reply_markup=keyboard) 61 | else: 62 | await message.reply_text( 63 | "♻ Usage:\n\n➩ /add_redeem 1min 1,\n➩ /add_redeem 1hour 10,\n➩ /add_redeem 1day 5" 64 | ) 65 | 66 | 67 | @Client.on_message(filters.command("redeem")) 68 | async def redeem_code(client, message): 69 | user_id = message.from_user.id 70 | if len(message.command) == 2: 71 | redeem_code = message.command[1] 72 | 73 | if redeem_code in VALID_REDEEM_CODES: 74 | try: 75 | time = VALID_REDEEM_CODES.pop(redeem_code) 76 | user = await client.get_users(user_id) 77 | 78 | try: 79 | seconds = await get_seconds(time) 80 | except Exception: 81 | await message.reply_text("Invalid time format in redeem code.") 82 | return 83 | 84 | if seconds > 0: 85 | data = await db.get_user(user_id) 86 | current_expiry = data.get("expiry_time") if data else None 87 | 88 | now_aware = datetime.now(pytz.utc) 89 | 90 | if current_expiry: 91 | current_expiry = current_expiry.replace(tzinfo=pytz.utc) 92 | 93 | if current_expiry and current_expiry > now_aware: 94 | expiry_str_in_ist = current_expiry.astimezone( 95 | pytz.timezone("Asia/Kolkata") 96 | ).strftime("%d-%m-%Y\n⏱️ Expiry Time: %I:%M:%S %p") 97 | await message.reply_text( 98 | f"🚫 You already have premium access, which expires on {expiry_str_in_ist}.\nYou cannot redeem another code until your current premium expires.", 99 | disable_web_page_preview=True, 100 | ) 101 | return 102 | 103 | expiry_time = now_aware + timedelta(seconds=seconds) 104 | user_data = {"id": user_id, "expiry_time": expiry_time} 105 | await db.update_user(user_data) 106 | 107 | expiry_str_in_ist = expiry_time.astimezone( 108 | pytz.timezone("Asia/Kolkata") 109 | ).strftime("%d-%m-%Y\n⏱️ Expiry Time: %I:%M:%S %p") 110 | 111 | await message.reply_text( 112 | f"Premium activated successfully!\n\nUser: {user.mention}\nUser ID: {user_id}\nPremium Access: {time}\n\nExpiry Date: {expiry_str_in_ist}", 113 | disable_web_page_preview=True, 114 | ) 115 | 116 | await client.send_message( 117 | LOG_CHANNEL, 118 | text=f"#Redeem_Premium\n\n👤 User: {user.mention}\n⚡ User ID: {user_id}\n⏰ Premium Access: {time}\n⌛️ Expiry Date: {expiry_str_in_ist}", 119 | disable_web_page_preview=True, 120 | ) 121 | else: 122 | await message.reply_text("Invalid time format in redeem code.") 123 | except Exception as e: 124 | await message.reply_text( 125 | f"An error occurred while redeeming the code: {e}" 126 | ) 127 | else: 128 | await message.reply_text("Invalid Redeem Code or Expired.") 129 | else: 130 | await message.reply_text("Usage: /redeem ") 131 | -------------------------------------------------------------------------------- /database/ia_filterdb.py: -------------------------------------------------------------------------------- 1 | from struct import pack 2 | import re 3 | import base64 4 | from pyrogram.file_id import FileId 5 | from pymongo.errors import DuplicateKeyError 6 | from umongo import Instance, Document, fields 7 | from motor.motor_asyncio import AsyncIOMotorClient 8 | from marshmallow.exceptions import ValidationError 9 | from info import FILES_DATABASE, DATABASE_NAME, COLLECTION_NAME, MAX_BTN 10 | 11 | client = AsyncIOMotorClient(FILES_DATABASE) 12 | mydb = client[DATABASE_NAME] 13 | instance = Instance.from_db(mydb) 14 | 15 | 16 | @instance.register 17 | class Media(Document): 18 | file_id = fields.StrField(attribute="_id") 19 | file_ref = fields.StrField(allow_none=True) 20 | file_name = fields.StrField(required=True) 21 | file_size = fields.IntField(required=True) 22 | mime_type = fields.StrField(allow_none=True) 23 | caption = fields.StrField(allow_none=True) 24 | file_type = fields.StrField(allow_none=True) 25 | 26 | class Meta: 27 | indexes = ("$file_name",) 28 | collection_name = COLLECTION_NAME 29 | 30 | 31 | async def get_files_db_size(): 32 | return (await mydb.command("dbstats"))["dataSize"] 33 | 34 | 35 | async def save_file(media): 36 | """Save file in database""" 37 | 38 | # TODO: Find better way to get same file_id for same media to avoid duplicates 39 | file_id, file_ref = unpack_new_file_id(media.file_id) 40 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 41 | try: 42 | file = Media( 43 | file_id=file_id, 44 | file_ref=file_ref, 45 | file_name=file_name, 46 | file_size=media.file_size, 47 | mime_type=media.mime_type, 48 | caption=media.caption.html if media.caption else None, 49 | file_type=media.mime_type.split("/")[0], 50 | ) 51 | except ValidationError: 52 | print("Error occurred while saving file in database") 53 | return "err" 54 | else: 55 | try: 56 | await file.commit() 57 | except DuplicateKeyError: 58 | print( 59 | f'{getattr(media, "file_name", "NO_FILE")} is already saved in database' 60 | ) 61 | return "dup" 62 | else: 63 | print(f'{getattr(media, "file_name", "NO_FILE")} is saved to database') 64 | return "suc" 65 | 66 | 67 | async def get_search_results(query, max_results=MAX_BTN, offset=0, lang=None): 68 | query = query.strip() 69 | if not query: 70 | raw_pattern = "." 71 | elif " " not in query: 72 | raw_pattern = r"(\b|[\.\+\-_])" + query + r"(\b|[\.\+\-_])" 73 | else: 74 | raw_pattern = query.replace(" ", r".*[\s\.\+\-_]") 75 | try: 76 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 77 | except: 78 | regex = query 79 | filter = {"file_name": regex} 80 | cursor = Media.find(filter) 81 | cursor.sort("$natural", -1) 82 | if lang: 83 | lang_files = [file async for file in cursor if lang in file.file_name.lower()] 84 | files = lang_files[offset:][:max_results] 85 | total_results = len(lang_files) 86 | next_offset = offset + max_results 87 | if next_offset >= total_results: 88 | next_offset = "" 89 | return files, next_offset, total_results 90 | cursor.skip(offset).limit(max_results) 91 | files = await cursor.to_list(length=max_results) 92 | total_results = await Media.count_documents(filter) 93 | next_offset = offset + max_results 94 | if next_offset >= total_results: 95 | next_offset = "" 96 | return files, next_offset, total_results 97 | 98 | 99 | async def get_bad_files(query, file_type=None, offset=0, filter=False): 100 | query = query.strip() 101 | if not query: 102 | raw_pattern = "." 103 | elif " " not in query: 104 | raw_pattern = r"(\b|[\.\+\-_])" + query + r"(\b|[\.\+\-_])" 105 | else: 106 | raw_pattern = query.replace(" ", r".*[\s\.\+\-_]") 107 | try: 108 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 109 | except: 110 | return [] 111 | filter = {"file_name": regex} 112 | if file_type: 113 | filter["file_type"] = file_type 114 | total_results = await Media.count_documents(filter) 115 | cursor = Media.find(filter) 116 | cursor.sort("$natural", -1) 117 | files = await cursor.to_list(length=total_results) 118 | return files, total_results 119 | 120 | 121 | async def get_file_details(query): 122 | filter = {"file_id": query} 123 | cursor = Media.find(filter) 124 | filedetails = await cursor.to_list(length=1) 125 | return filedetails 126 | 127 | 128 | def encode_file_id(s: bytes) -> str: 129 | r = b"" 130 | n = 0 131 | for i in s + bytes([22]) + bytes([4]): 132 | if i == 0: 133 | n += 1 134 | else: 135 | if n: 136 | r += b"\x00" + bytes([n]) 137 | n = 0 138 | r += bytes([i]) 139 | return base64.urlsafe_b64encode(r).decode().rstrip("=") 140 | 141 | 142 | def encode_file_ref(file_ref: bytes) -> str: 143 | return base64.urlsafe_b64encode(file_ref).decode().rstrip("=") 144 | 145 | 146 | def unpack_new_file_id(new_file_id): 147 | """Return file_id, file_ref""" 148 | decoded = FileId.decode(new_file_id) 149 | file_id = encode_file_id( 150 | pack( 151 | "☤ ᴛʜᴀɴᴋ ʏᴏᴜ ꜰᴏʀ ᴀᴅᴅɪɴɢ ᴍᴇ ɪɴ {message.chat.title}\n\n🤖 ᴅᴏɴ’ᴛ ꜰᴏʀɢᴇᴛ ᴛᴏ ᴍᴀᴋᴇ ᴍᴇ ᴀᴅᴍɪɴ 🤖\n\n㊝ ɪꜰ ʏᴏᴜ ʜᴀᴠᴇ ᴀɴʏ ᴅᴏᴜʙᴛ ʏᴏᴜ ᴄʟᴇᴀʀ ɪᴛ ᴜsɪɴɢ ʙᴇʟᴏᴡ ʙᴜᴛᴛᴏɴs ㊜
", 40 | reply_markup=reply_markup, 41 | ) 42 | 43 | 44 | @Client.on_message(filters.command("leave") & filters.user(ADMINS)) 45 | async def leave_a_chat(bot, message): 46 | r = message.text.split(None) 47 | if len(message.command) == 1: 48 | return await message.reply( 49 | "ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ ʟɪᴋᴇ ᴛʜɪꜱ `/leave -100******`" 50 | ) 51 | if len(r) > 2: 52 | reason = message.text.split(None, 2)[2] 53 | chat = message.text.split(None, 2)[1] 54 | else: 55 | chat = message.command[1] 56 | reason = "ɴᴏ ʀᴇᴀꜱᴏɴ ᴘʀᴏᴠɪᴅᴇᴅ..." 57 | try: 58 | chat = int(chat) 59 | except: 60 | chat = chat 61 | try: 62 | btn = [[InlineKeyboardButton("⚡️ ᴏᴡɴᴇʀ ⚡️", url=USERNAME)]] 63 | reply_markup = InlineKeyboardMarkup(btn) 64 | await bot.send_message( 65 | chat_id=chat, 66 | text=f"😞 ʜᴇʟʟᴏ ᴅᴇᴀʀ,\nᴍʏ ᴏᴡɴᴇʀ ʜᴀꜱ ᴛᴏʟᴅ ᴍᴇ ᴛᴏ ʟᴇᴀᴠᴇ ꜰʀᴏᴍ ɢʀᴏᴜᴘ ꜱᴏ ɪ ɢᴏ 😔\n\n🚫 ʀᴇᴀꜱᴏɴ ɪꜱ - {reason}\n\nɪꜰ ʏᴏᴜ ɴᴇᴇᴅ ᴛᴏ ᴀᴅᴅ ᴍᴇ ᴀɢᴀɪɴ ᴛʜᴇɴ ᴄᴏɴᴛᴀᴄᴛ ᴍʏ ᴏᴡɴᴇʀ 👇", 67 | reply_markup=reply_markup, 68 | ) 69 | await bot.leave_chat(chat) 70 | await db.delete_chat(chat) 71 | await message.reply(f"ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ʟᴇꜰᴛ ꜰʀᴏᴍ ɢʀᴏᴜᴘ - `{chat}`") 72 | except Exception as e: 73 | await message.reply(f"🚫 ᴇʀʀᴏʀ - `{e}`") 74 | 75 | 76 | @Client.on_message(filters.command("groups") & filters.user(ADMINS)) 77 | async def groups_list(bot, message): 78 | msg = await message.reply("Searching...") 79 | chats = await db.get_all_chats() 80 | out = "Groups saved in the database:\n\n" 81 | count = 1 82 | async for chat in chats: 83 | chat_info = await bot.get_chat(chat["id"]) 84 | members_count = ( 85 | chat_info.members_count if chat_info.members_count else "Unknown" 86 | ) 87 | out += f"{count}. Title - `{chat['title']}`\nID - `{chat['id']}`\nMembers - `{members_count}`" 88 | out += "\n\n" 89 | count += 1 90 | try: 91 | if count > 1: 92 | await msg.edit_text(out) 93 | else: 94 | await msg.edit_text("No groups found") 95 | except MessageTooLong: 96 | with open("chats.txt", "w+") as outfile: 97 | outfile.write(out) 98 | await message.reply_document("chats.txt", caption="List of all groups") 99 | 100 | 101 | @Client.on_message(filters.command("stats") & filters.user(ADMINS) & filters.incoming) 102 | async def get_ststs(bot, message): 103 | users = await db.total_users_count() 104 | groups = await db.total_chat_count() 105 | size = get_size(await db.get_db_size()) 106 | free = get_size(536870912) 107 | files = await Media.count_documents() 108 | db2_size = get_size(await get_files_db_size()) 109 | db2_free = get_size(536870912) 110 | uptime = time.strftime("%Hh %Mm %Ss", time.gmtime(time.time() - time.time())) 111 | ram = psutil.virtual_memory().percent 112 | cpu = psutil.cpu_percent() 113 | await message.reply_text( 114 | script.STATUS_TXT.format( 115 | users, groups, size, free, files, db2_size, db2_free, uptime, ram, cpu 116 | ) 117 | ) 118 | 119 | 120 | @Client.on_message(filters.command("invite") & filters.private & filters.user(ADMINS)) 121 | async def invite(client, message): 122 | toGenInvLink = message.command[1] 123 | if len(toGenInvLink) != 14: 124 | return await message.reply( 125 | "Invalid chat id\nAdd -100 before chat id if You did not add any yet." 126 | ) 127 | try: 128 | link = await client.export_chat_invite_link(toGenInvLink) 129 | await message.reply(link) 130 | except Exception as e: 131 | print(f"Error while generating invite link : {e}\nFor chat:{toGenInvLink}") 132 | await message.reply( 133 | f"Error while generating invite link : {e}\nFor chat:{toGenInvLink}" 134 | ) 135 | -------------------------------------------------------------------------------- /plugins/route.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | import re 3 | import math 4 | import logging 5 | import secrets 6 | import mimetypes 7 | from aiohttp.http_exceptions import BadStatusLine 8 | from Jisshu.bot import multi_clients, work_loads 9 | from Jisshu.server.exceptions import FIleNotFound, InvalidHash 10 | from Jisshu.util.custom_dl import ByteStreamer 11 | from Jisshu.util.render_template import render_page 12 | from info import * 13 | 14 | 15 | routes = web.RouteTableDef() 16 | 17 | 18 | @routes.get("/", allow_head=True) 19 | async def root_route_handler(request): 20 | return web.json_response("InfinityBotzz ~ EDITH") 21 | 22 | 23 | @routes.get(r"/watch/{path:\S+}", allow_head=True) 24 | async def stream_handler(request: web.Request): 25 | try: 26 | path = request.match_info["path"] 27 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path) 28 | if match: 29 | secure_hash = match.group(1) 30 | id = int(match.group(2)) 31 | else: 32 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1)) 33 | secure_hash = request.rel_url.query.get("hash") 34 | return web.Response( 35 | text=await render_page(id, secure_hash), content_type="text/html" 36 | ) 37 | except InvalidHash as e: 38 | raise web.HTTPForbidden(text=e.message) 39 | except FIleNotFound as e: 40 | raise web.HTTPNotFound(text=e.message) 41 | except (AttributeError, BadStatusLine, ConnectionResetError): 42 | pass 43 | except Exception as e: 44 | logging.critical(e.with_traceback(None)) 45 | raise web.HTTPInternalServerError(text=str(e)) 46 | 47 | 48 | @routes.get(r"/{path:\S+}", allow_head=True) 49 | async def stream_handler(request: web.Request): 50 | try: 51 | path = request.match_info["path"] 52 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path) 53 | if match: 54 | secure_hash = match.group(1) 55 | id = int(match.group(2)) 56 | else: 57 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1)) 58 | secure_hash = request.rel_url.query.get("hash") 59 | return await media_streamer(request, id, secure_hash) 60 | except InvalidHash as e: 61 | raise web.HTTPForbidden(text=e.message) 62 | except FIleNotFound as e: 63 | raise web.HTTPNotFound(text=e.message) 64 | except (AttributeError, BadStatusLine, ConnectionResetError): 65 | pass 66 | except Exception as e: 67 | logging.critical(e.with_traceback(None)) 68 | raise web.HTTPInternalServerError(text=str(e)) 69 | 70 | 71 | class_cache = {} 72 | 73 | 74 | async def media_streamer(request: web.Request, id: int, secure_hash: str): 75 | range_header = request.headers.get("Range", 0) 76 | 77 | index = min(work_loads, key=work_loads.get) 78 | faster_client = multi_clients[index] 79 | 80 | if MULTI_CLIENT: 81 | logging.info(f"Client {index} is now serving {request.remote}") 82 | 83 | if faster_client in class_cache: 84 | tg_connect = class_cache[faster_client] 85 | logging.debug(f"Using cached ByteStreamer object for client {index}") 86 | else: 87 | logging.debug(f"Creating new ByteStreamer object for client {index}") 88 | tg_connect = ByteStreamer(faster_client) 89 | class_cache[faster_client] = tg_connect 90 | logging.debug("before calling get_file_properties") 91 | file_id = await tg_connect.get_file_properties(id) 92 | logging.debug("after calling get_file_properties") 93 | 94 | if file_id.unique_id[:6] != secure_hash: 95 | logging.debug(f"Invalid hash for message with ID {id}") 96 | raise InvalidHash 97 | 98 | file_size = file_id.file_size 99 | 100 | if range_header: 101 | from_bytes, until_bytes = range_header.replace("bytes=", "").split("-") 102 | from_bytes = int(from_bytes) 103 | until_bytes = int(until_bytes) if until_bytes else file_size - 1 104 | else: 105 | from_bytes = request.http_range.start or 0 106 | until_bytes = (request.http_range.stop or file_size) - 1 107 | 108 | if (until_bytes > file_size) or (from_bytes < 0) or (until_bytes < from_bytes): 109 | return web.Response( 110 | status=416, 111 | body="416: Range not satisfiable", 112 | headers={"Content-Range": f"bytes */{file_size}"}, 113 | ) 114 | 115 | chunk_size = 1024 * 1024 116 | until_bytes = min(until_bytes, file_size - 1) 117 | 118 | offset = from_bytes - (from_bytes % chunk_size) 119 | first_part_cut = from_bytes - offset 120 | last_part_cut = until_bytes % chunk_size + 1 121 | 122 | req_length = until_bytes - from_bytes + 1 123 | part_count = math.ceil(until_bytes / chunk_size) - math.floor(offset / chunk_size) 124 | body = tg_connect.yield_file( 125 | file_id, index, offset, first_part_cut, last_part_cut, part_count, chunk_size 126 | ) 127 | 128 | mime_type = file_id.mime_type 129 | file_name = file_id.file_name 130 | disposition = "attachment" 131 | 132 | if mime_type: 133 | if not file_name: 134 | try: 135 | file_name = f"{secrets.token_hex(2)}.{mime_type.split('/')[1]}" 136 | except (IndexError, AttributeError): 137 | file_name = f"{secrets.token_hex(2)}.unknown" 138 | else: 139 | if file_name: 140 | mime_type = mimetypes.guess_type(file_id.file_name) 141 | else: 142 | mime_type = "application/octet-stream" 143 | file_name = f"{secrets.token_hex(2)}.unknown" 144 | 145 | return web.Response( 146 | status=206 if range_header else 200, 147 | body=body, 148 | headers={ 149 | "Content-Type": f"{mime_type}", 150 | "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}", 151 | "Content-Length": str(req_length), 152 | "Content-Disposition": f'{disposition}; filename="{file_name}"', 153 | "Accept-Ranges": "bytes", 154 | }, 155 | ) 156 | -------------------------------------------------------------------------------- /plugins/broadcast.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | import time 3 | from database.users_chats_db import db 4 | from info import ADMINS 5 | from utils import users_broadcast, groups_broadcast, temp, get_readable_time 6 | import asyncio 7 | from pyrogram.types import ( 8 | InlineKeyboardButton, 9 | InlineKeyboardMarkup, 10 | ReplyKeyboardMarkup, 11 | ) 12 | 13 | lock = asyncio.Lock() 14 | 15 | 16 | @Client.on_callback_query(filters.regex(r"^broadcast_cancel")) 17 | async def broadcast_cancel(bot, query): 18 | _, ident = query.data.split("#") 19 | if ident == "users": 20 | await query.message.edit("ᴛʀʏɪɴɢ ᴛᴏ ᴄᴀɴᴄᴇʟ ᴜsᴇʀs ʙʀᴏᴀᴅᴄᴀsᴛɪɴɢ...") 21 | temp.USERS_CANCEL = True 22 | elif ident == "groups": 23 | temp.GROUPS_CANCEL = True 24 | await query.message.edit("ᴛʀʏɪɴɢ ᴛᴏ ᴄᴀɴᴄᴇʟ ɢʀᴏᴜᴘs ʙʀᴏᴀᴅᴄᴀsᴛɪɴɢ...") 25 | 26 | 27 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply) 28 | async def broadcast_users(bot, message): 29 | if lock.locked(): 30 | return await message.reply("Currently broadcast processing, Wait for complete.") 31 | 32 | msg = await message.ask( 33 | "Do you want pin this message in users?", 34 | reply_markup=ReplyKeyboardMarkup( 35 | [["Yes", "No"]], one_time_keyboard=True, resize_keyboard=True 36 | ), 37 | ) 38 | if msg.text == "Yes": 39 | is_pin = True 40 | elif msg.text == "No": 41 | is_pin = False 42 | else: 43 | return await msg.edit("Wrong Response!") 44 | await msg.delete() 45 | users = await db.get_all_users() 46 | b_msg = message.reply_to_message 47 | b_sts = await message.reply_text( 48 | text="ʙʀᴏᴀᴅᴄᴀsᴛɪɴɢ ʏᴏᴜʀ ᴍᴇssᴀɢᴇs ᴛᴏ ᴜsᴇʀs ⌛️" 49 | ) 50 | start_time = time.time() 51 | total_users = await db.total_users_count() 52 | done = 0 53 | blocked = 0 54 | deleted = 0 55 | failed = 0 56 | success = 0 57 | 58 | async with lock: 59 | async for user in users: 60 | time_taken = get_readable_time(time.time() - start_time) 61 | if temp.USERS_CANCEL: 62 | temp.USERS_CANCEL = False 63 | await b_sts.edit( 64 | f"Users broadcast Cancelled!\nCompleted in {time_taken}\n\nTotal Users: {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}" 65 | ) 66 | return 67 | sts = await users_broadcast(int(user["id"]), b_msg, is_pin) 68 | if sts == "Success": 69 | success += 1 70 | elif sts == "Error": 71 | failed += 1 72 | done += 1 73 | if not done % 80: 74 | btn = [ 75 | [ 76 | InlineKeyboardButton( 77 | "CANCEL", callback_data="broadcast_cancel#users" 78 | ) 79 | ] 80 | ] 81 | await b_sts.edit( 82 | f"Users broadcast in progress...\n\nTotal Users: {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}", 83 | reply_markup=InlineKeyboardMarkup(btn), 84 | ) 85 | await b_sts.edit( 86 | f"Users broadcast completed.\nCompleted in {time_taken}\n\nTotal Users: {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}" 87 | ) 88 | 89 | 90 | @Client.on_message( 91 | filters.command("grp_broadcast") & filters.user(ADMINS) & filters.reply 92 | ) 93 | async def broadcast_group(bot, message): 94 | msg = await message.ask( 95 | "Do you want pin this message in groups?", 96 | reply_markup=ReplyKeyboardMarkup( 97 | [["Yes", "No"]], one_time_keyboard=True, resize_keyboard=True 98 | ), 99 | ) 100 | if msg.text == "Yes": 101 | is_pin = True 102 | elif msg.text == "No": 103 | is_pin = False 104 | else: 105 | return await msg.edit("Wrong Response!") 106 | await msg.delete() 107 | chats = await db.get_all_chats() 108 | b_msg = message.reply_to_message 109 | b_sts = await message.reply_text( 110 | text="ʙʀᴏᴀᴅᴄᴀsᴛɪɴɢ ʏᴏᴜʀ ᴍᴇssᴀɢᴇs ᴛᴏ ɢʀᴏᴜᴘs ⏳" 111 | ) 112 | start_time = time.time() 113 | total_chats = await db.total_chat_count() 114 | done = 0 115 | failed = 0 116 | success = 0 117 | 118 | async with lock: 119 | async for chat in chats: 120 | time_taken = get_readable_time(time.time() - start_time) 121 | if temp.GROUPS_CANCEL: 122 | temp.GROUPS_CANCEL = False 123 | await b_sts.edit( 124 | f"Groups broadcast Cancelled!\nCompleted in {time_taken}\n\nTotal Groups: {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}" 125 | ) 126 | return 127 | sts = await groups_broadcast(int(chat["id"]), b_msg, is_pin) 128 | if sts == "Success": 129 | success += 1 130 | elif sts == "Error": 131 | failed += 1 132 | done += 1 133 | if not done % 30: 134 | btn = [ 135 | [ 136 | InlineKeyboardButton( 137 | "CANCEL", callback_data="broadcast_cancel#groups" 138 | ) 139 | ] 140 | ] 141 | await b_sts.edit( 142 | f"Groups groadcast in progress...\n\nTotal Groups: {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}", 143 | reply_markup=InlineKeyboardMarkup(btn), 144 | ) 145 | await b_sts.edit( 146 | f"Groups broadcast completed.\nCompleted in {time_taken}\n\nTotal Groups: {total_chats}\nCompleted: {done} / {total_chats}\nSuccess: {success}\nFailed: {failed}" 147 | ) 148 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Jisshu-Auto-filter 3 |

4 |

5 | Jisshu Auto Filter Bot 6 |

7 | 8 | ### 🤖 Bot Commands 9 | 10 |
/commands Enter this command inside the bot and all the commands will be set automatically. 11 | 12 | ``` 13 | start - Start The Bot  14 | most - Get Most Searches Button List  15 | trend - Get Top Trending Button List  16 | mostlist - Show Most Searches List  17 | trendlist - 𝖦𝖾𝗍 𝖳𝗈𝗉 𝖳𝗋𝖾𝗇𝖽𝗂𝗇𝗀 𝖡𝗎𝗍𝗍𝗈𝗇 𝖫𝗂𝗌𝗍  18 | plan - Check Available Premium Membership Plans  19 | myplan - Check Your Current Plan  20 | refer - To Refer Your Friend And Get Premium  21 | stats - Check My Database  22 | id - Get Telegram Id  23 | font - To Generate Cool Fonts  24 | details - Check Group Details  25 | settings - Change Bot Setting  26 | grp_cmds - Check Group Commands  27 | admin_cmds - Bot Admin Commands 28 | ``` 29 |
30 | 31 | ## **Futures** 32 |
Check Bot Futures 33 |
34 | 35 | - [x] 𝑺𝒉𝒐𝒓𝒕𝒏𝒆𝒓 𝑺𝒖𝒑𝒑𝒐𝒓𝒕 𝒊𝒏 𝑺𝒕𝒓𝒆𝒂𝒎 𝒂𝒏𝒅 𝑫𝒐𝒘𝒏𝒍𝒐𝒂𝒅 𝒇𝒆𝒂𝒕𝒖𝒓𝒆 36 | - [x] 𝑮𝒐𝒐𝒅 𝑴𝒐𝒓𝒏𝒊𝒏𝒈, 𝑨𝒇𝒕𝒆𝒓𝒏𝒐𝒐𝒏, 𝑬𝒗𝒆𝒏𝒊𝒏𝒈, 𝑵𝒊𝒈𝒉𝒕 𝒘𝒊𝒔𝒉𝒆𝒔 37 | - [x] 𝑹𝒆𝒒𝒖𝒆𝒔𝒕 𝒕𝒐 𝒋𝒐𝒊𝒏 𝒊𝒏 𝑭𝒔𝒖𝒃 38 | - [x] 𝑩𝒆𝒔𝒕 𝑺𝒕𝒓𝒆𝒂𝒎𝒊𝒏𝒈 𝑾𝒆𝒃𝒔𝒊𝒕𝒆 39 | - [x] 𝑷𝒓𝒆𝒎𝒊𝒖𝒎 𝒎𝒆𝒎𝒃𝒆𝒓𝒔𝒉𝒊𝒑 𝒎𝒂𝒏𝒂𝒈𝒆𝒎𝒆𝒏𝒕 40 | - [x] 𝐶𝑢𝑠𝑡𝑜𝑚 𝑆ℎ𝑜𝑟𝑡𝑛𝑒𝑟 ( 𝐴𝑙𝑙 𝑊𝑒𝑏𝑠𝑖𝑡𝑒𝑠 ) 41 | - [x] 𝑆𝑡𝑟𝑒𝑎𝑚 𝑜𝑛𝑙𝑖𝑛𝑒 𝑎𝑛𝑑 𝐹𝑎𝑠𝑡 𝐷𝑜𝑤𝑛𝑙𝑜𝑎𝑑 42 | - [x] 𝐼𝑀𝐷𝐵 𝑇𝑒𝑚𝑝𝑙𝑎𝑡𝑒 𝑆𝑒𝑡 43 | - [x] 𝑃𝑟𝑒𝐷𝑉𝐷 𝑎𝑛𝑑 𝐶𝑎𝑚𝑅𝑖𝑝 𝐷𝑒𝑙𝑒𝑡𝑒 𝑀𝑜𝑑𝑒 44 | - [x] 𝑀𝑢𝑙𝑡𝑖𝑝𝑙𝑒 𝐹𝑖𝑙𝑒 𝐷𝑒𝑙𝑒𝑡𝑖𝑜𝑛 45 | - [x] 𝑆𝑒𝑡𝑡𝑖𝑛𝑔𝑠 𝑀𝑒𝑛𝑢 46 | - [x] 𝐹𝑜𝑟𝑐𝑒 𝑆𝑢𝑏𝑠𝑐𝑟𝑖𝑝𝑡𝑖𝑜𝑛 47 | - [x] 𝑊𝑒𝑙𝑐𝑜𝑚𝑒 𝑀𝑒𝑠𝑠𝑎𝑔𝑒 48 | - [x] 𝐴𝑢𝑡𝑜𝑚𝑎𝑡𝑖𝑐 𝐹𝑖𝑙𝑒 𝐹𝑖𝑙𝑡𝑒𝑟𝑖𝑛𝑔 49 | - [x] 𝐷𝑜𝑢𝑏𝑙𝑒 𝐹𝑖𝑙𝑡𝑒𝑟 𝐵𝑢𝑡𝑡𝑜𝑛 50 | - [x] 𝑆𝑖𝑛𝑔𝑙𝑒 𝐹𝑖𝑙𝑡𝑒𝑟 𝐵𝑢𝑡𝑡𝑜𝑛 51 | - [x] 𝐵𝑜𝑡 𝑃𝑀 𝐹𝑖𝑙𝑒 𝑆𝑒𝑛𝑑 𝑀𝑜𝑑𝑒 52 | - [x] 𝐴𝑢𝑡𝑜 𝐹𝑖𝑙𝑒 𝑆𝑒𝑛𝑑 53 | - [x] 𝐹𝑜𝑟𝑤𝑎𝑟𝑑 𝑅𝑒𝑠𝑡𝑟𝑖𝑐𝑡𝑖𝑜𝑛 54 | - [x] 𝐹𝑖𝑙𝑒 𝑃𝑟𝑜𝑡𝑒𝑐𝑡 55 | - [x] 𝑀𝑎𝑛𝑢𝑎𝑙 𝐹𝑖𝑙𝑒 𝐹𝑖𝑙𝑡𝑒𝑟𝑖𝑛𝑔 56 | - [x] 𝐴𝑑𝑚𝑖𝑛 𝐶𝑜𝑚𝑚𝑎𝑛𝑑𝑠 57 | - [x] 𝑈𝑠𝑒𝑟 𝐵𝑟𝑜𝑎𝑑𝑐𝑎𝑠𝑡 58 | - [x] 𝐺𝑟𝑜𝑢𝑝 𝐵𝑟𝑜𝑎𝑑𝑐𝑎𝑠𝑡 59 | - [x] 𝐼𝑛𝑑𝑒𝑥 60 | - [x] 𝐼𝑛𝑙𝑖𝑛𝑒 𝑆𝑒𝑎𝑟𝑐ℎ 61 | - [x] 𝑅𝑎𝑛𝑑𝑜𝑚 𝑝𝑖𝑐𝑠 62 | - [x] 𝑖𝑑𝑠 𝑎𝑛𝑑 𝑈𝑠𝑒𝑟 𝑖𝑛𝑓𝑜 63 | - [x] 𝑆𝑡𝑎𝑡𝑠 64 | - [x] 𝑈𝑠𝑒𝑟𝑠 65 | - [x] 𝐶ℎ𝑎𝑡𝑠 66 | - [x] 𝑈𝑠𝑒𝑟 𝐵𝑎𝑛 67 | - [x] 𝑈𝑠𝑒𝑟 𝑈𝑛𝑏𝑎𝑛 68 | - [x] 𝐶ℎ𝑎𝑡 𝐿𝑒𝑎𝑣𝑒 69 | - [x] 𝐶ℎ𝑎𝑡 𝐷𝑖𝑠𝑎𝑏𝑙𝑒 70 | - [x] Ai.𝑆𝑝𝑒𝑙𝑙𝑖𝑛𝑔 𝐶ℎ𝑒𝑐𝑘 𝐹𝑒𝑎𝑡𝑢𝑟𝑒 71 | - [x] 𝐴𝑢𝑡𝑜 𝐷𝑒𝑙𝑒𝑡𝑒 72 | - [x] Refer future 73 | - [x] Redeem Code Future 74 | - [x] Top Trending future 75 | - [x] Most Search 76 | - [x] Set ads 77 | - [x] 𝐴𝑛𝑑 𝑀𝑜𝑟𝑒... 78 |
79 | 80 | ## Futures Screenshot 81 | - Screenshot link - [Click Here](https://jisshuapis.vercel.app/screenshot.php) 82 | - Demo bot - [@NehaAutoBot](https://t.me/NehaAutoBot) 83 | 84 | ## Variables 85 | 86 | ### Required Variables 87 | * `BOT_TOKEN`: Create a bot using [@BotFather](https://telegram.dog/BotFather), and get the Telegram API token. 88 | * `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) 89 | * `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) 90 | * `CHANNELS`: ID of channel for Auto Indexing. Separate multiple IDs by space. Make sure bot is admin. 91 | * `ADMINS`: ID of Admin. Separate multiple Admins by space. 92 | * `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) 93 | * `DATABASE_NAME`: Name of the database in [mongoDB](https://www.mongodb.com). 94 | * `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. 95 | 96 | 97 |
Deploy To Heroku 98 |

99 |
100 | 101 | Deploy To Heroku 102 | 103 |

104 |
105 | 106 |
Deploy To Koyeb 107 |
108 | The fastest way to deploy the application is to click the Deploy to Koyeb button below. 109 |
110 |
111 | 112 | [![Deploy to Koyeb](https://www.koyeb.com/static/images/deploy/button.svg)](https://app.koyeb.com/deploy?type=git&repository=github.com/JisshuTG/Jisshu-filter-bot&branch=main&name=Jisshu-filter-bot ) 113 |
114 | 115 |
Deploy To Render 116 |
117 | 118 | Use these commands: 119 |
120 |
121 | • Build Command: pip3 install -U -r requirements.txt 122 |
123 |
124 | • Start Command: python3 bot.py 125 |
126 |
127 | Go to https://uptimerobot.com/ and add a monitor to keep your bot alive. 128 |
129 |
130 | Use these settings when adding a monitor:
131 |
132 |
133 | render template 134 |
135 |
136 | Click on the below button to deploy directly to render ↓ 137 |
138 |
139 | 140 | Deploy to Render 141 | 142 |
143 | 144 |
Deploy To VPS 145 |

146 |

147 | git clone https://github.com/JisshuTG/Jisshu-filter-bot
148 | # Install Packages
149 | pip3 install -U -r requirements.txt
150 | Edit info.py with variables as given below then run bot
151 | python3 bot.py
152 | 
153 |

154 |
155 | 156 | ## **Special Thanks to** 157 | 158 | - thanks to [Jisshu Developer](https://t.me/JISSHU_BOTS) (myself) for modifying the repo and adding powerful new features. 159 | - Thanks to [Ꭺɴᴏɴʏᴍᴏᴜꜱ](https://t.me/@BeingXAnonymous) for contributing innovative features and consistently helping improve the project. 160 | - Thanks to [𝐌ʀ 𝐈ɴғɪɴɪᴛʏ](https://t.me/infinitymp07) for identifying and fixing important issues, ensuring better performance and stability. 161 | 162 | 163 |

ᴄᴏɴᴛᴀᴄᴛ ᴍᴇ

164 | 165 | [](https://telegram.im/@JISSHU_BOTS) [](https://github.com/JisshuTG) [](https://www.youtube.com/@JISSHU-BOTS) [](https://www.instagram.com/jhaplustar?igsh=MW9neHowNWo1Ymt6NA==) 166 | -------------------------------------------------------------------------------- /plugins/index.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyrogram import Client, filters, enums 3 | from pyrogram.errors import FloodWait 4 | from info import ADMINS, CHANNELS 5 | from database.ia_filterdb import save_file 6 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 7 | from utils import temp, get_readable_time 8 | import time 9 | 10 | lock = asyncio.Lock() 11 | 12 | 13 | @Client.on_callback_query(filters.regex(r"^index")) 14 | async def index_files(bot, query): 15 | _, ident, chat, lst_msg_id, skip = query.data.split("#") 16 | if ident == "yes": 17 | msg = query.message 18 | await msg.edit("Indexing started...") 19 | try: 20 | chat = int(chat) 21 | except: 22 | chat = chat 23 | await index_files_to_db(int(lst_msg_id), chat, msg, bot, int(skip)) 24 | elif ident == "cancel": 25 | temp.CANCEL = True 26 | await query.message.edit("Trying to cancel Indexing...") 27 | 28 | 29 | @Client.on_message( 30 | filters.command("index") & filters.private & filters.incoming & filters.user(ADMINS) 31 | ) 32 | async def send_for_index(bot, message): 33 | if lock.locked(): 34 | return await message.reply("Wait until previous process complete.") 35 | i = await message.reply("Forward last message or send last message link.") 36 | msg = await bot.listen(chat_id=message.chat.id, user_id=message.from_user.id) 37 | await i.delete() 38 | if msg.text and msg.text.startswith("https://t.me"): 39 | try: 40 | msg_link = msg.text.split("/") 41 | last_msg_id = int(msg_link[-1]) 42 | chat_id = msg_link[-2] 43 | if chat_id.isnumeric(): 44 | chat_id = int(("-100" + chat_id)) 45 | except: 46 | await message.reply("Invalid message link!") 47 | return 48 | elif msg.forward_from_chat and msg.forward_from_chat.type == enums.ChatType.CHANNEL: 49 | last_msg_id = msg.forward_from_message_id 50 | chat_id = msg.forward_from_chat.username or msg.forward_from_chat.id 51 | else: 52 | await message.reply("This is not forwarded message or link.") 53 | return 54 | try: 55 | chat = await bot.get_chat(chat_id) 56 | except Exception as e: 57 | return await message.reply(f"Errors - {e}") 58 | if chat.type != enums.ChatType.CHANNEL: 59 | return await message.reply("I can index only channels.") 60 | s = await message.reply("Send skip message number.") 61 | msg = await bot.listen(chat_id=message.chat.id, user_id=message.from_user.id) 62 | await s.delete() 63 | try: 64 | skip = int(msg.text) 65 | except: 66 | return await message.reply("Number is invalid.") 67 | buttons = [ 68 | [ 69 | InlineKeyboardButton( 70 | "YES", callback_data=f"index#yes#{chat_id}#{last_msg_id}#{skip}" 71 | ) 72 | ], 73 | [ 74 | InlineKeyboardButton("CLOSE", callback_data="close_data"), 75 | ], 76 | ] 77 | reply_markup = InlineKeyboardMarkup(buttons) 78 | await message.reply( 79 | f"Do you want to index {chat.title} channel?\nTotal Messages: {last_msg_id}", 80 | reply_markup=reply_markup, 81 | ) 82 | 83 | 84 | @Client.on_message(filters.command("channel")) 85 | async def channel_info(bot, message): 86 | if message.from_user.id not in ADMINS: 87 | await message.reply("ᴏɴʟʏ ᴛʜᴇ ʙᴏᴛ ᴏᴡɴᴇʀ ᴄᴀɴ ᴜsᴇ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ... 😑") 88 | return 89 | ids = CHANNELS 90 | if not ids: 91 | return await message.reply("Not set CHANNELS") 92 | text = "**Indexed Channels:**\n\n" 93 | for id in ids: 94 | chat = await bot.get_chat(id) 95 | text += f"{chat.title}\n" 96 | text += f"\n**Total:** {len(ids)}" 97 | await message.reply(text) 98 | 99 | 100 | async def index_files_to_db(lst_msg_id, chat, msg, bot, skip): 101 | start_time = time.time() 102 | total_files = 0 103 | duplicate = 0 104 | errors = 0 105 | deleted = 0 106 | no_media = 0 107 | unsupported = 0 108 | current = skip 109 | 110 | async with lock: 111 | try: 112 | async for message in bot.iter_messages(chat, lst_msg_id, skip): 113 | time_taken = get_readable_time(time.time() - start_time) 114 | if temp.CANCEL: 115 | temp.CANCEL = False 116 | await msg.edit( 117 | f"Successfully Cancelled!\nCompleted in {time_taken}\n\nSaved {total_files} files to Database!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}\nUnsupported Media: {unsupported}\nErrors Occurred: {errors}" 118 | ) 119 | return 120 | current += 1 121 | if current % 100 == 0: 122 | btn = [ 123 | [ 124 | InlineKeyboardButton( 125 | "CANCEL", 126 | callback_data=f"index#cancel#{chat}#{lst_msg_id}#{skip}", 127 | ) 128 | ] 129 | ] 130 | await msg.edit_text( 131 | text=f"Total messages received: {current}\nTotal messages saved: {total_files}\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}\nUnsupported Media: {unsupported}\nErrors Occurred: {errors}", 132 | reply_markup=InlineKeyboardMarkup(btn), 133 | ) 134 | await asyncio.sleep(2) 135 | if message.empty: 136 | deleted += 1 137 | continue 138 | elif not message.media: 139 | no_media += 1 140 | continue 141 | elif message.media not in [ 142 | enums.MessageMediaType.VIDEO, 143 | enums.MessageMediaType.DOCUMENT, 144 | ]: 145 | unsupported += 1 146 | continue 147 | media = getattr(message, message.media.value, None) 148 | if not media: 149 | unsupported += 1 150 | continue 151 | elif media.mime_type not in ["video/mp4", "video/x-matroska"]: 152 | unsupported += 1 153 | continue 154 | media.caption = message.caption 155 | sts = await save_file(media) 156 | if sts == "suc": 157 | total_files += 1 158 | elif sts == "dup": 159 | duplicate += 1 160 | elif sts == "err": 161 | errors += 1 162 | except FloodWait as e: 163 | await asyncio.sleep(e.x) 164 | except Exception as e: 165 | await msg.reply(f"Index canceled due to Error - {e}") 166 | else: 167 | time_taken = get_readable_time(time.time() - start_time) 168 | await msg.edit( 169 | f"Succesfully saved {total_files} to Database!\nCompleted in {time_taken}\n\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}\nUnsupported Media: {unsupported}\nErrors Occurred: {errors}" 170 | ) 171 | -------------------------------------------------------------------------------- /plugins/helper/font.py: -------------------------------------------------------------------------------- 1 | from plugins.helper.fotnt_string import Fonts 2 | from pyrogram import Client, filters 3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 4 | 5 | 6 | @Client.on_message(filters.private & filters.command(["font"])) 7 | async def style_buttons(c, m, cb=False): 8 | buttons = [ 9 | [ 10 | InlineKeyboardButton("𝚃𝚢𝚙𝚎𝚠𝚛𝚒𝚝𝚎𝚛", callback_data="style+typewriter"), 11 | InlineKeyboardButton("𝕆𝕦𝕥𝕝𝕚𝕟𝕖", callback_data="style+outline"), 12 | InlineKeyboardButton("𝐒𝐞𝐫𝐢𝐟", callback_data="style+serif"), 13 | ], 14 | [ 15 | InlineKeyboardButton("𝑺𝒆𝒓𝒊𝒇", callback_data="style+bold_cool"), 16 | InlineKeyboardButton("𝑆𝑒𝑟𝑖𝑓", callback_data="style+cool"), 17 | InlineKeyboardButton("Sᴍᴀʟʟ Cᴀᴘs", callback_data="style+small_cap"), 18 | ], 19 | [ 20 | InlineKeyboardButton("𝓈𝒸𝓇𝒾𝓅𝓉", callback_data="style+script"), 21 | InlineKeyboardButton("𝓼𝓬𝓻𝓲𝓹𝓽", callback_data="style+script_bolt"), 22 | InlineKeyboardButton("ᵗⁱⁿʸ", callback_data="style+tiny"), 23 | ], 24 | [ 25 | InlineKeyboardButton("ᑕOᗰIᑕ", callback_data="style+comic"), 26 | InlineKeyboardButton("𝗦𝗮𝗻𝘀", callback_data="style+sans"), 27 | InlineKeyboardButton("𝙎𝙖𝙣𝙨", callback_data="style+slant_sans"), 28 | ], 29 | [ 30 | InlineKeyboardButton("𝘚𝘢𝘯𝘴", callback_data="style+slant"), 31 | InlineKeyboardButton("𝖲𝖺𝗇𝗌", callback_data="style+sim"), 32 | InlineKeyboardButton("Ⓒ︎Ⓘ︎Ⓡ︎Ⓒ︎Ⓛ︎Ⓔ︎Ⓢ︎", callback_data="style+circles"), 33 | ], 34 | [ 35 | InlineKeyboardButton("🅒︎🅘︎🅡︎🅒︎🅛︎🅔︎🅢︎", callback_data="style+circle_dark"), 36 | InlineKeyboardButton("𝔊𝔬𝔱𝔥𝔦𝔠", callback_data="style+gothic"), 37 | InlineKeyboardButton("𝕲𝖔𝖙𝖍𝖎𝖈", callback_data="style+gothic_bolt"), 38 | ], 39 | [ 40 | InlineKeyboardButton("C͜͡l͜͡o͜͡u͜͡d͜͡s͜͡", callback_data="style+cloud"), 41 | InlineKeyboardButton("H̆̈ă̈p̆̈p̆̈y̆̈", callback_data="style+happy"), 42 | InlineKeyboardButton("S̑̈ȃ̈d̑̈", callback_data="style+sad"), 43 | ], 44 | [InlineKeyboardButton("Next ➡️", callback_data="nxt")], 45 | ] 46 | if not cb: 47 | if " " in m.text: 48 | title = m.text.split(" ", 1)[1] 49 | await m.reply_text( 50 | title, 51 | reply_markup=InlineKeyboardMarkup(buttons), 52 | reply_to_message_id=m.id, 53 | ) 54 | else: 55 | await m.reply_text(text="Ente Any Text Eg:- `/font [text]`") 56 | else: 57 | await m.answer() 58 | await m.message.edit_reply_markup(InlineKeyboardMarkup(buttons)) 59 | 60 | 61 | @Client.on_callback_query(filters.regex("^nxt")) 62 | async def nxt(c, m): 63 | if m.data == "nxt": 64 | buttons = [ 65 | [ 66 | InlineKeyboardButton("🇸 🇵 🇪 🇨 🇮 🇦 🇱 ", callback_data="style+special"), 67 | InlineKeyboardButton("🅂🅀🅄🄰🅁🄴🅂", callback_data="style+squares"), 68 | InlineKeyboardButton("🆂︎🆀︎🆄︎🅰︎🆁︎🅴︎🆂︎", callback_data="style+squares_bold"), 69 | ], 70 | [ 71 | InlineKeyboardButton("ꪖꪀᦔꪖꪶꪊᥴ𝓲ꪖ", callback_data="style+andalucia"), 72 | InlineKeyboardButton("爪卂几ᘜ卂", callback_data="style+manga"), 73 | InlineKeyboardButton("S̾t̾i̾n̾k̾y̾", callback_data="style+stinky"), 74 | ], 75 | [ 76 | InlineKeyboardButton("B̥ͦu̥ͦb̥ͦb̥ͦl̥ͦe̥ͦs̥ͦ", callback_data="style+bubbles"), 77 | InlineKeyboardButton("U͟n͟d͟e͟r͟l͟i͟n͟e͟", callback_data="style+underline"), 78 | InlineKeyboardButton("꒒ꍏꀷꌩꌃꀎꁅ", callback_data="style+ladybug"), 79 | ], 80 | [ 81 | InlineKeyboardButton("R҉a҉y҉s҉", callback_data="style+rays"), 82 | InlineKeyboardButton("B҈i҈r҈d҈s҈", callback_data="style+birds"), 83 | InlineKeyboardButton("S̸l̸a̸s̸h̸", callback_data="style+slash"), 84 | ], 85 | [ 86 | InlineKeyboardButton("s⃠t⃠o⃠p⃠", callback_data="style+stop"), 87 | InlineKeyboardButton("S̺͆k̺͆y̺͆l̺͆i̺͆n̺͆e̺͆", callback_data="style+skyline"), 88 | InlineKeyboardButton("A͎r͎r͎o͎w͎s͎", callback_data="style+arrows"), 89 | ], 90 | [ 91 | InlineKeyboardButton("ዪሀክቿነ", callback_data="style+qvnes"), 92 | InlineKeyboardButton("S̶t̶r̶i̶k̶e̶", callback_data="style+strike"), 93 | InlineKeyboardButton("F༙r༙o༙z༙e༙n༙", callback_data="style+frozen"), 94 | ], 95 | [InlineKeyboardButton("⬅️ Back", callback_data="nxt+0")], 96 | ] 97 | await m.answer() 98 | await m.message.edit_reply_markup(InlineKeyboardMarkup(buttons)) 99 | else: 100 | await style_buttons(c, m, cb=True) 101 | 102 | 103 | @Client.on_callback_query(filters.regex("^style")) 104 | async def style(c, m): 105 | await m.answer() 106 | cmd, style = m.data.split("+") 107 | 108 | if style == "typewriter": 109 | cls = Fonts.typewriter 110 | if style == "outline": 111 | cls = Fonts.outline 112 | if style == "serif": 113 | cls = Fonts.serief 114 | if style == "bold_cool": 115 | cls = Fonts.bold_cool 116 | if style == "cool": 117 | cls = Fonts.cool 118 | if style == "small_cap": 119 | cls = Fonts.smallcap 120 | if style == "script": 121 | cls = Fonts.script 122 | if style == "script_bolt": 123 | cls = Fonts.bold_script 124 | if style == "tiny": 125 | cls = Fonts.tiny 126 | if style == "comic": 127 | cls = Fonts.comic 128 | if style == "sans": 129 | cls = Fonts.san 130 | if style == "slant_sans": 131 | cls = Fonts.slant_san 132 | if style == "slant": 133 | cls = Fonts.slant 134 | if style == "sim": 135 | cls = Fonts.sim 136 | if style == "circles": 137 | cls = Fonts.circles 138 | if style == "circle_dark": 139 | cls = Fonts.dark_circle 140 | if style == "gothic": 141 | cls = Fonts.gothic 142 | if style == "gothic_bolt": 143 | cls = Fonts.bold_gothic 144 | if style == "cloud": 145 | cls = Fonts.cloud 146 | if style == "happy": 147 | cls = Fonts.happy 148 | if style == "sad": 149 | cls = Fonts.sad 150 | if style == "special": 151 | cls = Fonts.special 152 | if style == "squares": 153 | cls = Fonts.square 154 | if style == "squares_bold": 155 | cls = Fonts.dark_square 156 | if style == "andalucia": 157 | cls = Fonts.andalucia 158 | if style == "manga": 159 | cls = Fonts.manga 160 | if style == "stinky": 161 | cls = Fonts.stinky 162 | if style == "bubbles": 163 | cls = Fonts.bubbles 164 | if style == "underline": 165 | cls = Fonts.underline 166 | if style == "ladybug": 167 | cls = Fonts.ladybug 168 | if style == "rays": 169 | cls = Fonts.rays 170 | if style == "birds": 171 | cls = Fonts.birds 172 | if style == "slash": 173 | cls = Fonts.slash 174 | if style == "stop": 175 | cls = Fonts.stop 176 | if style == "skyline": 177 | cls = Fonts.skyline 178 | if style == "arrows": 179 | cls = Fonts.arrows 180 | if style == "qvnes": 181 | cls = Fonts.rvnes 182 | if style == "strike": 183 | cls = Fonts.strike 184 | if style == "frozen": 185 | cls = Fonts.frozen 186 | 187 | r, oldtxt = m.message.reply_to_message.text.split(None, 1) 188 | new_text = cls(oldtxt) 189 | try: 190 | await m.message.edit_text( 191 | f"`{new_text}`\n\n👆 Click To Copy", reply_markup=m.message.reply_markup 192 | ) 193 | except Exception as e: 194 | print(e) 195 | -------------------------------------------------------------------------------- /info.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import environ 3 | from Script import script 4 | 5 | id_pattern = re.compile(r"^.\d+$") 6 | 7 | 8 | def is_enabled(value, default): 9 | if value.lower() in ["true", "yes", "1", "enable", "y"]: 10 | return True 11 | elif value.lower() in ["false", "no", "0", "disable", "n"]: 12 | return False 13 | else: 14 | return default 15 | 16 | 17 | # Main 18 | SESSION = environ.get("SESSION", "Media_search") 19 | API_ID = int(environ.get("API_ID", "")) 20 | API_HASH = environ.get("API_HASH", "") 21 | BOT_TOKEN = environ.get("BOT_TOKEN", "") 22 | PORT = environ.get("PORT", "8082") 23 | 24 | # Owners 25 | ADMINS = [ 26 | int(admin) if id_pattern.search(admin) else admin 27 | for admin in environ.get("ADMINS", "5672857559").split() 28 | ] 29 | OWNER_USERNAME = environ.get( 30 | "OWNER_USERNAME", "IM_JISSHU" 31 | ) # without @ or https://t.me/ 32 | USERNAME = environ.get("USERNAME", "") # ADMIN USERNAME 33 | 34 | # Database Channel 35 | CHANNELS = [ 36 | int(ch) if id_pattern.search(ch) else ch 37 | for ch in environ.get("CHANNELS", "").split() 38 | ] 39 | 40 | # ForceSub Channel & Log Channels 41 | AUTH_CHANNEL = int(environ.get("AUTH_CHANNEL", "")) 42 | AUTH_REQ_CHANNEL = int(environ.get("AUTH_REQ_CHANNEL", "")) 43 | LOG_CHANNEL = int(environ.get("LOG_CHANNEL", "")) 44 | LOG_API_CHANNEL = int(environ.get("LOG_API_CHANNEL", "")) 45 | LOG_VR_CHANNEL = int(environ.get("LOG_VR_CHANNEL", "")) 46 | 47 | # MongoDB 48 | DATABASE_URI = environ.get("DATABASE_URI", "") 49 | DATABASE_NAME = environ.get("DATABASE_NAME", "Cluster0") 50 | 51 | # Files index database url 52 | FILES_DATABASE = environ.get("FILES_DATABASE", "") 53 | COLLECTION_NAME = environ.get("COLLECTION_NAME", "jisshu") 54 | 55 | # Other Channel's 56 | SUPPORT_GROUP = int(environ.get("SUPPORT_GROUP", "-1001864434358")) 57 | DELETE_CHANNELS = int(environ.get("DELETE_CHANNELS", "0")) 58 | request_channel = environ.get("REQUEST_CHANNEL", "-1001864434358") 59 | REQUEST_CHANNEL = ( 60 | int(request_channel) 61 | if request_channel and id_pattern.search(request_channel) 62 | else None 63 | ) 64 | MOVIE_UPDATE_CHANNEL = int(environ.get("MOVIE_UPDATE_CHANNEL", "-1001864434358")) 65 | 66 | # Added Link Here Not Id 67 | SUPPORT_CHAT = environ.get("SUPPORT_CHAT", "") 68 | MOVIE_GROUP_LINK = environ.get("MOVIE_GROUP_LINK", "") 69 | 70 | # Verification 71 | IS_VERIFY = is_enabled("IS_VERIFY", True) 72 | # --------------------------------------------------------------- 73 | TUTORIAL = environ.get("TUTORIAL", "https://t.me/") 74 | TUTORIAL_2 = environ.get("TUTORIAL_2", "https://t.me/") 75 | TUTORIAL_3 = environ.get("TUTORIAL_3", "https://t.me/") 76 | VERIFY_IMG = environ.get( 77 | "VERIFY_IMG", "https://graph.org/file/1669ab9af68eaa62c3ca4.jpg" 78 | ) 79 | SHORTENER_API = environ.get("SHORTENER_API", "3097623f852197a9ce40d1212aaa8bbf2803e799") 80 | SHORTENER_WEBSITE = environ.get("SHORTENER_WEBSITE", "omegalinks.in") 81 | SHORTENER_API2 = environ.get( 82 | "SHORTENER_API2", "3097623f852197a9ce40d1212aaa8bbf2803e799" 83 | ) 84 | SHORTENER_WEBSITE2 = environ.get("SHORTENER_WEBSITE2", "omegalinks.in") 85 | SHORTENER_API3 = environ.get( 86 | "SHORTENER_API3", "3097623f852197a9ce40d1212aaa8bbf2803e799" 87 | ) 88 | SHORTENER_WEBSITE3 = environ.get("SHORTENER_WEBSITE3", "omegalinks.in") 89 | TWO_VERIFY_GAP = int(environ.get("TWO_VERIFY_GAP", "14400")) 90 | THREE_VERIFY_GAP = int(environ.get("THREE_VERIFY_GAP", "14400")) 91 | 92 | # Language & Quality & Season & Year 93 | LANGUAGES = [ 94 | "hindi", 95 | "english", 96 | "telugu", 97 | "tamil", 98 | "kannada", 99 | "malayalam", 100 | "bengali", 101 | "marathi", 102 | "gujarati", 103 | "punjabi", 104 | "marathi", 105 | ] 106 | QUALITIES = [ 107 | "HdRip", 108 | "web-dl", 109 | "bluray", 110 | "hdr", 111 | "fhd", 112 | "240p", 113 | "360p", 114 | "480p", 115 | "540p", 116 | "720p", 117 | "960p", 118 | "1080p", 119 | "1440p", 120 | "2K", 121 | "2160p", 122 | "4k", 123 | "5K", 124 | "8K", 125 | ] 126 | YEARS = [f"{i}" for i in range(2025, 2002, -1)] 127 | SEASONS = [f"season {i}" for i in range(1, 23)] 128 | 129 | # Pictures And Reaction 130 | START_IMG = ( 131 | environ.get( 132 | "START_IMG", 133 | "https://i.ibb.co/qpxpGmC/image.jpg https://i.ibb.co/DQ35zLZ/image.jpg", 134 | ) 135 | ).split() 136 | FORCESUB_IMG = environ.get("FORCESUB_IMG", "https://i.ibb.co/ZNC1Hnb/ad3f2c88a8f2.jpg") 137 | REFER_PICS = (environ.get("REFER_PICS", "https://envs.sh/PSI.jpg")).split() 138 | PAYPICS = ( 139 | environ.get("PAYPICS", "https://graph.org/file/f4db1c3ad3d9e38b328e6.jpg") 140 | ).split() 141 | SUBSCRIPTION = environ.get( 142 | "SUBSCRIPTION", "https://graph.org/file/9f3f47c690bbcc67633c2.jpg" 143 | ) 144 | REACTIONS = ["👀", "😱", "🔥", "😍", "🎉", "🥰", "😇", "⚡"] 145 | 146 | 147 | # Other Funtions 148 | FILE_AUTO_DEL_TIMER = int(environ.get("FILE_AUTO_DEL_TIMER", "600")) 149 | AUTO_FILTER = is_enabled("AUTO_FILTER", True) 150 | IS_PM_SEARCH = is_enabled("IS_PM_SEARCH", False) 151 | IS_SEND_MOVIE_UPDATE = is_enabled( 152 | "IS_SEND_MOVIE_UPDATE", False 153 | ) # Don't Change It ( If You Want To Turn It On Then Turn It On By Commands) We Suggest You To Make It Turn Off If You Are Indexing Files First Time. 154 | MAX_BTN = int(environ.get("MAX_BTN", "8")) 155 | AUTO_DELETE = is_enabled("AUTO_DELETE", True) 156 | DELETE_TIME = int(environ.get("DELETE_TIME", 1200)) 157 | IMDB = is_enabled("IMDB", False) 158 | FILE_CAPTION = environ.get("FILE_CAPTION", f"{script.FILE_CAPTION}") 159 | IMDB_TEMPLATE = environ.get("IMDB_TEMPLATE", f"{script.IMDB_TEMPLATE_TXT}") 160 | LONG_IMDB_DESCRIPTION = is_enabled("LONG_IMDB_DESCRIPTION", False) 161 | PROTECT_CONTENT = is_enabled("PROTECT_CONTENT", False) 162 | SPELL_CHECK = is_enabled("SPELL_CHECK", True) 163 | LINK_MODE = is_enabled("LINK_MODE", True) 164 | TMDB_API_KEY = environ.get("TMDB_API_KEY", "") 165 | 166 | # Online Streaming And Download 167 | STREAM_MODE = bool(environ.get("STREAM_MODE", True)) # Set True or Flase 168 | 169 | MULTI_CLIENT = False 170 | SLEEP_THRESHOLD = int(environ.get("SLEEP_THRESHOLD", "60")) 171 | PING_INTERVAL = int(environ.get("PING_INTERVAL", "1200")) # 20 minutes 172 | if "DYNO" in environ: 173 | ON_HEROKU = True 174 | else: 175 | ON_HEROKU = False 176 | URL = environ.get("FQDN", "") 177 | 178 | # Commands 179 | admin_cmds = [ 180 | "/add_premium - Add A User To Premium", 181 | "/premium_users - View All Premium Users", 182 | "/remove_premium - Remove A User's Premium Status", 183 | "/add_redeem - Generate A Redeem Code", 184 | "/refresh - Refresh Free Trail", 185 | "/set_muc - Set Movie Update Channel", 186 | "/pm_search_on - Enable PM Search", 187 | "/pm_search_off - Disable PM Search", 188 | "/set_ads - Set Advertisements", 189 | "/del_ads - Delete Advertisements", 190 | "/setlist - Set Top Trending List", 191 | "/clearlist - Clear Top Trending List", 192 | "/verify_id - Verification Off ID", 193 | "/index - Index Files", 194 | "/send - Send Message To A User", 195 | "/leave - Leave A Group Or Channel", 196 | "/ban - Ban A User", 197 | "/unban - Unban A User", 198 | "/broadcast - Broadcast Message", 199 | "/grp_broadcast - Broadcast Messages To Groups", 200 | "/delreq - Delete Join Request", 201 | "/channel - List Of Database Channels", 202 | "/del_file - Delete A Specific File", 203 | "/delete - Delete A File(By Reply)", 204 | "/deletefiles - Delete Multiple Files", 205 | "/deleteall - Delete All Files", 206 | ] 207 | 208 | cmds = [ 209 | {"start": "Start The Bot"}, 210 | {"most": "Get Most Searches Button List"}, 211 | {"trend": "Get Top Trending Button List"}, 212 | {"mostlist": "Show Most Searches List"}, 213 | {"trendlist": "𝖦𝖾𝗍 𝖳𝗈𝗉 𝖳𝗋𝖾𝗇𝖽𝗂𝗇𝗀 𝖡𝗎𝗍𝗍𝗈𝗇 𝖫𝗂𝗌t"}, 214 | {"plan": "Check Available Premium Membership Plans"}, 215 | {"myplan": "Check Your Currunt Plan"}, 216 | {"refer": "To Refer Your Friend And Get Premium"}, 217 | {"stats": "Check My Database"}, 218 | {"id": "Get Telegram Id"}, 219 | {"font": "To Generate Cool Fonts"}, 220 | {"details": "Check Group Details"}, 221 | {"settings": "Change Bot Setting"}, 222 | {"grp_cmds": "Check Group Commands"}, 223 | {"admin_cmds": "Bot Admin Commands"}, 224 | ] 225 | -------------------------------------------------------------------------------- /Jisshu/template/dl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{file_name}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 33 |
34 |
35 | WELCOME 36 | CHANNELS 37 | CONTACT 38 |
39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 |
47 |

File Name:

48 |

{{file_name}}


49 |

File Size:

50 |

{{file_size}}

51 |
52 |
53 | 56 | 59 | 62 | 65 | 68 |
69 | 70 |
71 |
72 |
73 |
74 | 75 |
76 |

WELCOME TO OUR FILE STREAM BOT

77 |

78 | This is a Telegram Bot to Stream Movies and Series directly on 79 | Telegram. You can also 80 | download them if you want. This bot is developed by ZISHAN 82 |

If you like this bot, then don't 83 | forget to share it with your friends and family. 84 |

85 |
86 | 87 | 104 | 105 | 113 | 114 |
115 |
116 |
117 |
118 |
119 |
120 | 121 |
122 |
123 |
124 | 125 |
126 |
127 | 128 |
129 |
130 |
131 |
132 |
133 | 134 |
135 |
136 |
137 | 138 |
139 | 140 |
141 | 142 |
143 | 148 |
149 |
150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /Jisshu/util/custom_dl.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from info import * 4 | from typing import Dict, Union 5 | from Jisshu.bot import work_loads 6 | from pyrogram import Client, utils, raw 7 | from .file_properties import get_file_ids 8 | from pyrogram.session import Session, Auth 9 | from pyrogram.errors import AuthBytesInvalid 10 | from Jisshu.server.exceptions import FIleNotFound 11 | from pyrogram.file_id import FileId, FileType, ThumbnailSource 12 | 13 | 14 | class ByteStreamer: 15 | def __init__(self, client: Client): 16 | """A custom class that holds the cache of a specific client and class functions. 17 | attributes: 18 | client: the client that the cache is for. 19 | cached_file_ids: a dict of cached file IDs. 20 | cached_file_properties: a dict of cached file properties. 21 | 22 | functions: 23 | generate_file_properties: returns the properties for a media of a specific message contained in Tuple. 24 | generate_media_session: returns the media session for the DC that contains the media file. 25 | yield_file: yield a file from telegram servers for streaming. 26 | 27 | This is a modified version of the 28 | Thanks to Eyaadh 29 | """ 30 | self.clean_timer = 30 * 60 31 | self.client: Client = client 32 | self.cached_file_ids: Dict[int, FileId] = {} 33 | asyncio.create_task(self.clean_cache()) 34 | 35 | async def get_file_properties(self, id: int) -> FileId: 36 | """ 37 | Returns the properties of a media of a specific message in a FIleId class. 38 | if the properties are cached, then it'll return the cached results. 39 | or it'll generate the properties from the Message ID and cache them. 40 | """ 41 | if id not in self.cached_file_ids: 42 | await self.generate_file_properties(id) 43 | logging.debug(f"Cached file properties for message with ID {id}") 44 | return self.cached_file_ids[id] 45 | 46 | async def generate_file_properties(self, id: int) -> FileId: 47 | """ 48 | Generates the properties of a media file on a specific message. 49 | returns ths properties in a FIleId class. 50 | """ 51 | file_id = await get_file_ids(self.client, LOG_CHANNEL, id) 52 | logging.debug(f"Generated file ID and Unique ID for message with ID {id}") 53 | if not file_id: 54 | logging.debug(f"Message with ID {id} not found") 55 | raise FIleNotFound 56 | self.cached_file_ids[id] = file_id 57 | logging.debug(f"Cached media message with ID {id}") 58 | return self.cached_file_ids[id] 59 | 60 | async def generate_media_session(self, client: Client, file_id: FileId) -> Session: 61 | """ 62 | Generates the media session for the DC that contains the media file. 63 | This is required for getting the bytes from Telegram servers. 64 | """ 65 | 66 | media_session = client.media_sessions.get(file_id.dc_id, None) 67 | 68 | if media_session is None: 69 | if file_id.dc_id != await client.storage.dc_id(): 70 | media_session = Session( 71 | client, 72 | file_id.dc_id, 73 | await Auth( 74 | client, file_id.dc_id, await client.storage.test_mode() 75 | ).create(), 76 | await client.storage.test_mode(), 77 | is_media=True, 78 | ) 79 | await media_session.start() 80 | 81 | for _ in range(6): 82 | exported_auth = await client.invoke( 83 | raw.functions.auth.ExportAuthorization(dc_id=file_id.dc_id) 84 | ) 85 | 86 | try: 87 | await media_session.send( 88 | raw.functions.auth.ImportAuthorization( 89 | id=exported_auth.id, bytes=exported_auth.bytes 90 | ) 91 | ) 92 | break 93 | except AuthBytesInvalid: 94 | logging.debug( 95 | f"Invalid authorization bytes for DC {file_id.dc_id}" 96 | ) 97 | continue 98 | else: 99 | await media_session.stop() 100 | raise AuthBytesInvalid 101 | else: 102 | media_session = Session( 103 | client, 104 | file_id.dc_id, 105 | await client.storage.auth_key(), 106 | await client.storage.test_mode(), 107 | is_media=True, 108 | ) 109 | await media_session.start() 110 | logging.debug(f"Created media session for DC {file_id.dc_id}") 111 | client.media_sessions[file_id.dc_id] = media_session 112 | else: 113 | logging.debug(f"Using cached media session for DC {file_id.dc_id}") 114 | return media_session 115 | 116 | @staticmethod 117 | async def get_location(file_id: FileId) -> Union[ 118 | raw.types.InputPhotoFileLocation, 119 | raw.types.InputDocumentFileLocation, 120 | raw.types.InputPeerPhotoFileLocation, 121 | ]: 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 | async def clean_cache(self) -> None: 224 | """ 225 | function to clean the cache to reduce memory usage 226 | """ 227 | while True: 228 | await asyncio.sleep(self.clean_timer) 229 | self.cached_file_ids.clear() 230 | logging.debug("Cleaned the cache") 231 | -------------------------------------------------------------------------------- /plugins/Extra/premium.py: -------------------------------------------------------------------------------- 1 | import pytz 2 | import datetime 3 | from Script import script 4 | from info import ADMINS, LOG_CHANNEL 5 | from utils import get_seconds 6 | from database.users_chats_db import db 7 | from pyrogram import Client, filters 8 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong 9 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 10 | 11 | 12 | @Client.on_message(filters.command("add_premium")) 13 | async def give_premium_cmd_handler(client, message): 14 | user_id = message.from_user.id 15 | if user_id not in ADMINS: 16 | await message.reply("ʏᴏᴜ ᴅᴏɴ'ᴛ ʜᴀᴠᴇ ᴀɴʏ ᴘᴇʀᴍɪꜱꜱɪᴏɴ ᴛᴏ ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ.") 17 | return 18 | if len(message.command) == 3: 19 | user_id = int(message.command[1]) # Convert the user_id to integer 20 | user = await client.get_users(user_id) 21 | time = message.command[2] 22 | seconds = await get_seconds(time) 23 | if seconds > 0: 24 | expiry_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds) 25 | user_data = {"id": user_id, "expiry_time": expiry_time} 26 | await db.update_user( 27 | user_data 28 | ) # Use the update_user method to update or insert user data 29 | await message.reply_text( 30 | f"ᴘʀᴇᴍɪᴜᴍ ᴀᴅᴅᴇᴅ ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ᴛᴏ ᴛʜᴇ ᴜꜱᴇʀꜱ.\n👤 ᴜꜱᴇʀ ɴᴀᴍᴇ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user.id}\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}" 31 | ) 32 | time_zone = datetime.datetime.now(pytz.timezone("Asia/Kolkata")) 33 | current_time = time_zone.strftime("%d-%m-%Y\n⏱️ ᴊᴏɪɴɪɴɢ ᴛɪᴍᴇ : %I:%M:%S %p") 34 | expiry = expiry_time 35 | expiry_str_in_ist = expiry.astimezone( 36 | pytz.timezone("Asia/Kolkata") 37 | ).strftime("%d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : %I:%M:%S %p") 38 | await client.send_message( 39 | chat_id=user_id, 40 | text=f"ᴘʀᴇᴍɪᴜᴍ ᴀᴅᴅᴇᴅ ᴛᴏ ʏᴏᴜʀ ᴀᴄᴄᴏᴜɴᴛ ꜰᴏʀ {time} ᴇɴᴊᴏʏ 😀\n\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}", 41 | ) 42 | # user = await client.get_users(user_id) 43 | await client.send_message( 44 | LOG_CHANNEL, 45 | text=f"#Added_Premium\n\n👤 ᴜꜱᴇʀ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user.id}\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}", 46 | disable_web_page_preview=True, 47 | ) 48 | 49 | else: 50 | await message.reply_text( 51 | "Invalid time format. Please use '1day for days', '1hour for hours', or '1min for minutes', or '1month for months' or '1year for year'" 52 | ) 53 | else: 54 | await message.reply_text( 55 | "Usage: /add_premium user_id time \n\nExample /add_premium 1252789 10day \n\n(e.g. for time units '1day for days', '1hour for hours', or '1min for minutes', or '1month for months' or '1year for year')" 56 | ) 57 | 58 | 59 | @Client.on_message(filters.command("myplan")) 60 | async def check_plans_cmd(client, message): 61 | user = message.from_user.mention 62 | user_id = message.from_user.id 63 | if await db.has_premium_access(user_id): 64 | remaining_time = await db.check_remaining_uasge(user_id) 65 | days = remaining_time.days 66 | hours, remainder = divmod(remaining_time.seconds, 3600) 67 | minutes, seconds = divmod(remainder, 60) 68 | formatted_remaining_time = ( 69 | f"{days} ᴅᴀʏꜱ, {hours} ʜᴏᴜʀꜱ, {minutes} ᴍɪɴᴜᴛᴇꜱ, {seconds} ꜱᴇᴄᴏɴᴅꜱ" 70 | ) 71 | expiry_time = remaining_time + datetime.datetime.now() 72 | expiry_date = expiry_time.astimezone(pytz.timezone("Asia/Kolkata")).strftime( 73 | "%d-%m-%Y" 74 | ) 75 | expiry_time = expiry_time.astimezone(pytz.timezone("Asia/Kolkata")).strftime( 76 | "%I:%M:%S %p" 77 | ) # Format time in IST (12-hour format) 78 | await message.reply_text( 79 | f"📝 ʏᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ ᴅᴇᴛᴀɪʟꜱ :\n\n👤 ᴜꜱᴇʀ ɴᴀᴍᴇ : {user}\n🏷️ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏱️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_date}\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : {expiry_time}\n⏳ ʀᴇᴍᴀɪɴɪɴɢ ᴛɪᴍᴇ : {formatted_remaining_time}" 80 | ) 81 | else: 82 | btn = [ 83 | [ 84 | InlineKeyboardButton( 85 | "ɢᴇᴛ ꜰʀᴇᴇ ᴛʀᴀɪʟ ꜰᴏʀ 𝟻 ᴍɪɴᴜᴛᴇꜱ ☺️", callback_data="give_trial" 86 | ) 87 | ], 88 | [ 89 | InlineKeyboardButton( 90 | "ʙᴜʏ sᴜʙsᴄʀɪᴘᴛɪᴏɴ : ʀᴇᴍᴏᴠᴇ ᴀᴅs", callback_data="seeplans" 91 | ) 92 | ], 93 | ] 94 | reply_markup = InlineKeyboardMarkup(btn) 95 | await message.reply_text( 96 | "😔 ʏᴏᴜ ᴅᴏɴ'ᴛ ʜᴀᴠᴇ ᴀɴʏ ᴘʀᴇᴍɪᴜᴍ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ. ɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ʙᴜʏ ᴘʀᴇᴍɪᴜᴍ ᴄʟɪᴄᴋ ᴏɴ ʙᴇʟᴏᴡ ʙᴜᴛᴛᴏɴ.\n\nᴛᴏ ᴜꜱᴇ ᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ꜰᴇᴀᴛᴜʀᴇꜱ ꜰᴏʀ 5 ᴍɪɴᴜᴛᴇꜱ ᴄʟɪᴄᴋ ᴏɴ ꜰʀᴇᴇ ᴛʀᴀɪʟ ʙᴜᴛᴛᴏɴ.", 97 | reply_markup=reply_markup, 98 | ) 99 | 100 | 101 | @Client.on_message(filters.command("remove_premium")) 102 | async def remove_premium(client, message): 103 | user_id = message.from_user.id 104 | if user_id not in ADMINS: 105 | await message.reply_text("ʏᴏᴜ ᴅᴏɴ'ᴛ ʜᴀᴠᴇ ᴀɴʏ ᴘᴇʀᴍɪꜱꜱɪᴏɴ ᴛᴏ ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ.") 106 | return 107 | if len(message.command) == 2: 108 | user_id = int(message.command[1]) # Convert the user_id to integer 109 | user = await client.get_users(user_id) 110 | if await db.remove_premium_access(user_id): 111 | await message.reply_text("ᴜꜱᴇʀ ʀᴇᴍᴏᴠᴇᴅ ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ !") 112 | await client.send_message( 113 | chat_id=user_id, 114 | text=f"ʜᴇʏ {user.mention},\n\nʏᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴ ʜᴀꜱ ʙᴇᴇɴ ᴇxᴘɪʀᴇᴅ.\n\nɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ʙᴜʏ ᴘʀᴇᴍɪᴜᴍ ᴀɢᴀɪɴ ᴛʜᴇɴ ᴄʟɪᴄᴋ ᴏɴ /plan ᴛᴏ ᴄʜᴇᴄᴋ ᴏᴜᴛ ᴏᴛʜᴇʀ ᴘʟᴀɴꜱ.", 115 | ) 116 | else: 117 | await message.reply_text( 118 | "ᴜɴᴀʙʟᴇ ᴛᴏ ʀᴇᴍᴏᴠᴇ ᴜꜱᴇʀ !\nᴀʀᴇ ʏᴏᴜ ꜱᴜʀᴇ, ɪᴛ ᴡᴀꜱ ᴀ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀ ɪᴅ ?" 119 | ) 120 | else: 121 | await message.reply_text("ᴜꜱᴀɢᴇ : /remove_premium user_id") 122 | 123 | 124 | @Client.on_message(filters.command("premium_users")) 125 | async def premium_users_info(client, message): 126 | user_id = message.from_user.id 127 | if user_id not in ADMINS: 128 | await message.reply("ʏᴏᴜ ᴅᴏɴ'ᴛ ʜᴀᴠᴇ ᴀɴʏ ᴘᴇʀᴍɪꜱꜱɪᴏɴ ᴛᴏ ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ.") 129 | return 130 | 131 | count = await db.all_premium_users() 132 | await message.reply( 133 | f"👥 ᴛᴏᴛᴀʟ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀꜱ - {count}\n\nᴘʟᴇᴀꜱᴇ ᴡᴀɪᴛ, ꜰᴇᴛᴄʜɪɴɢ ꜰᴜʟʟ ɪɴꜰᴏ ᴏꜰ ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀꜱ" 134 | ) 135 | 136 | users = await db.get_all_users() 137 | new = "📝 ᴘʀᴇᴍɪᴜᴍ ᴜꜱᴇʀꜱ ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ :\n\n" 138 | user_count = 1 139 | async for user in users: 140 | data = await db.get_user(user["id"]) 141 | if data and data.get("expiry_time"): 142 | expiry = data.get("expiry_time") 143 | expiry_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")) 144 | current_time = datetime.datetime.now(pytz.timezone("Asia/Kolkata")) 145 | 146 | if current_time > expiry_ist: 147 | await db.remove_premium_access( 148 | user["id"] 149 | ) # Remove premium access if expired 150 | continue # Skip the user if their expiry time has passed 151 | 152 | expiry_str_in_ist = expiry_ist.strftime("%d-%m-%Y") 153 | expiry_time_in_ist = expiry_ist.strftime("%I:%M:%S %p") 154 | time_left = expiry_ist - current_time 155 | 156 | days = time_left.days 157 | hours, remainder = divmod(time_left.seconds, 3600) 158 | minutes, seconds = divmod(remainder, 60) 159 | time_left_str = ( 160 | f"{days} ᴅᴀʏꜱ, {hours} ʜᴏᴜʀꜱ, {minutes} ᴍɪɴᴜᴛᴇꜱ, {seconds} ꜱᴇᴄᴏɴᴅꜱ" 161 | ) 162 | 163 | new += f"{user_count}. {(await client.get_users(user['id'])).mention}\n👤 ᴜꜱᴇʀ ɪᴅ : {user['id']}\n⏱️ ᴇxᴘɪʀᴇᴅ ᴅᴀᴛᴇ : {expiry_str_in_ist}\n⏱️ ᴇxᴘɪʀᴇᴅ ᴛɪᴍᴇ : {expiry_time_in_ist}\n⏳ ʀᴇᴍᴀɪɴɪɴɢ ᴛɪᴍᴇ : {time_left_str}\n\n" 164 | user_count += 1 165 | else: 166 | pass 167 | 168 | try: 169 | await message.reply(new) 170 | except MessageTooLong: 171 | with open("premium_users_info.txt", "w+") as outfile: 172 | outfile.write(new) 173 | await message.reply_document( 174 | "premium_users_info.txt", caption="Premium Users Information:" 175 | ) 176 | 177 | 178 | # Free Trail Remove ( Give Credit To - NBBotz ) 179 | @Client.on_message(filters.command("refresh")) 180 | async def reset_trial(client, message): 181 | user_id = message.from_user.id 182 | if user_id not in ADMINS: 183 | await message.reply("ʏᴏᴜ ᴅᴏɴ'ᴛ ʜᴀᴠᴇ ᴀɴʏ ᴘᴇʀᴍɪꜱꜱɪᴏɴ ᴛᴏ ᴜꜱᴇ ᴛʜɪꜱ ᴄᴏᴍᴍᴀɴᴅ.") 184 | return 185 | 186 | try: 187 | if len(message.command) > 1: 188 | target_user_id = int(message.command[1]) 189 | updated_count = await db.reset_free_trial(target_user_id) 190 | message_text = ( 191 | f"ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ʀᴇꜱᴇᴛ ꜰʀᴇᴇ ᴛʀᴀɪʟ ꜰᴏʀ ᴜꜱᴇʀꜱ {target_user_id}." 192 | if updated_count 193 | else f"ᴜꜱᴇʀ {target_user_id} ɴᴏᴛ ꜰᴏᴜɴᴅ ᴏʀ ᴅᴏɴ'ᴛ ᴄʟᴀɪᴍ ꜰʀᴇᴇ ᴛʀᴀɪʟ ʏᴇᴛ." 194 | ) 195 | else: 196 | updated_count = await db.reset_free_trial() 197 | message_text = f"ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ʀᴇꜱᴇᴛ ꜰʀᴇᴇ ᴛʀᴀɪʟ ꜰᴏʀ {updated_count} ᴜꜱᴇʀꜱ." 198 | 199 | await message.reply_text(message_text) 200 | except Exception as e: 201 | await message.reply_text(f"An error occurred: {e}") 202 | 203 | 204 | @Client.on_message(filters.command("plan")) 205 | async def plan(client, message): 206 | user_id = message.from_user.id 207 | users = message.from_user.mention 208 | btn = [ 209 | [InlineKeyboardButton("🍁 𝗖𝗹𝗶𝗰𝗸 𝗔𝗹𝗹 𝗣𝗹𝗮𝗻𝘀 & 𝗣𝗿𝗶𝗰𝗲𝘀 🍁", callback_data="free")], 210 | [InlineKeyboardButton("❌ ᴄʟᴏꜱᴇ ❌", callback_data="close_data")], 211 | ] 212 | await message.reply_photo( 213 | photo="https://graph.org/file/55a5392f88ec5a4bd3379.jpg", 214 | caption=script.PREPLANS_TXT.format(message.from_user.mention), 215 | reply_markup=InlineKeyboardMarkup(btn), 216 | ) 217 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyrogram.errors import ( 3 | InputUserDeactivated, 4 | UserNotParticipant, 5 | FloodWait, 6 | UserIsBlocked, 7 | PeerIdInvalid, 8 | ) 9 | from info import AUTH_CHANNEL, LONG_IMDB_DESCRIPTION, START_IMG 10 | from imdb import Cinemagoer 11 | import asyncio 12 | from pyrogram.types import Message 13 | from pyrogram import enums 14 | import pytz 15 | import re 16 | import os 17 | from shortzy import Shortzy 18 | from datetime import datetime 19 | from typing import Any 20 | from database.users_chats_db import db 21 | 22 | 23 | logger = logging.getLogger(__name__) 24 | logger.setLevel(logging.INFO) 25 | 26 | BANNED = {} 27 | imdb = Cinemagoer() 28 | 29 | 30 | class temp(object): 31 | ME = None 32 | CURRENT = int(os.environ.get("SKIP", 2)) 33 | CANCEL = False 34 | U_NAME = None 35 | B_NAME = None 36 | B_LINK = None 37 | SETTINGS = {} 38 | FILES_ID = {} 39 | USERS_CANCEL = False 40 | GROUPS_CANCEL = False 41 | CHAT = {} 42 | BANNED_USERS = [] 43 | BANNED_CHATS = [] 44 | 45 | 46 | def formate_file_name(file_name): 47 | file_name = " ".join( 48 | filter( 49 | lambda x: not x.startswith("[") 50 | and not x.startswith("@") 51 | and not x.startswith("www."), 52 | file_name.split(), 53 | ) 54 | ) 55 | return file_name 56 | 57 | 58 | async def is_req_subscribed(bot, query): 59 | if await db.find_join_req(query.from_user.id): 60 | return True 61 | try: 62 | user = await bot.get_chat_member(AUTH_CHANNEL, query.from_user.id) 63 | except UserNotParticipant: 64 | pass 65 | except Exception as e: 66 | print(e) 67 | else: 68 | if user.status != enums.ChatMemberStatus.BANNED: 69 | return True 70 | return False 71 | 72 | 73 | async def is_subscribed(bot, user_id, channel_id): 74 | try: 75 | user = await bot.get_chat_member(channel_id, user_id) 76 | except UserNotParticipant: 77 | pass 78 | except Exception: 79 | pass 80 | else: 81 | if user.status != enums.ChatMemberStatus.BANNED: 82 | return True 83 | return False 84 | 85 | 86 | async def get_poster(query, bulk=False, id=False, file=None): 87 | if not id: 88 | query = (query.strip()).lower() 89 | title = query 90 | year = re.findall(r"[1-2]\d{3}$", query, re.IGNORECASE) 91 | if year: 92 | year = list_to_str(year[:1]) 93 | title = (query.replace(year, "")).strip() 94 | elif file is not None: 95 | year = re.findall(r"[1-2]\d{3}", file, re.IGNORECASE) 96 | if year: 97 | year = list_to_str(year[:1]) 98 | else: 99 | year = None 100 | movieid = imdb.search_movie(title.lower(), results=10) 101 | if not movieid: 102 | return None 103 | if year: 104 | filtered = list(filter(lambda k: str(k.get("year")) == str(year), movieid)) 105 | if not filtered: 106 | filtered = movieid 107 | else: 108 | filtered = movieid 109 | movieid = list( 110 | filter(lambda k: k.get("kind") in ["movie", "tv series"], filtered) 111 | ) 112 | if not movieid: 113 | movieid = filtered 114 | if bulk: 115 | return movieid 116 | movieid = movieid[0].movieID 117 | else: 118 | movieid = query 119 | movie = imdb.get_movie(movieid) 120 | if movie.get("original air date"): 121 | date = movie["original air date"] 122 | elif movie.get("year"): 123 | date = movie.get("year") 124 | else: 125 | date = "N/A" 126 | plot = "" 127 | if not LONG_IMDB_DESCRIPTION: 128 | plot = movie.get("plot") 129 | if plot and len(plot) > 0: 130 | plot = plot[0] 131 | else: 132 | plot = movie.get("plot outline") 133 | if plot and len(plot) > 800: 134 | plot = plot[0:800] + "..." 135 | 136 | return { 137 | "title": movie.get("title"), 138 | "votes": movie.get("votes"), 139 | "aka": list_to_str(movie.get("akas")), 140 | "seasons": movie.get("number of seasons"), 141 | "box_office": movie.get("box office"), 142 | "localized_title": movie.get("localized title"), 143 | "kind": movie.get("kind"), 144 | "imdb_id": f"tt{movie.get('imdbID')}", 145 | "cast": list_to_str(movie.get("cast")), 146 | "runtime": list_to_str(movie.get("runtimes")), 147 | "countries": list_to_str(movie.get("countries")), 148 | "certificates": list_to_str(movie.get("certificates")), 149 | "languages": list_to_str(movie.get("languages")), 150 | "director": list_to_str(movie.get("director")), 151 | "writer": list_to_str(movie.get("writer")), 152 | "producer": list_to_str(movie.get("producer")), 153 | "composer": list_to_str(movie.get("composer")), 154 | "cinematographer": list_to_str(movie.get("cinematographer")), 155 | "music_team": list_to_str(movie.get("music department")), 156 | "distributors": list_to_str(movie.get("distributors")), 157 | "release_date": date, 158 | "year": movie.get("year"), 159 | "genres": list_to_str(movie.get("genres")), 160 | "poster": movie.get("full-size cover url", START_IMG), 161 | "plot": plot, 162 | "rating": str(movie.get("rating")), 163 | "url": f"https://www.imdb.com/title/tt{movieid}", 164 | } 165 | 166 | 167 | async def users_broadcast(user_id, message, is_pin): 168 | try: 169 | m = await message.copy(chat_id=user_id) 170 | if is_pin: 171 | await m.pin(both_sides=True) 172 | return True, "Success" 173 | except FloodWait as e: 174 | await asyncio.sleep(e.x) 175 | return await users_broadcast(user_id, message) 176 | except InputUserDeactivated: 177 | await db.delete_user(int(user_id)) 178 | logging.info(f"{user_id}-Removed from Database, since deleted account.") 179 | return False, "Deleted" 180 | except UserIsBlocked: 181 | await db.delete_user(int(user_id)) 182 | logging.info(f"{user_id} - Removed from Database, since Blocked the bot.") 183 | await db.delete_user(user_id) 184 | return False, "Blocked" 185 | except PeerIdInvalid: 186 | await db.delete_user(int(user_id)) 187 | logging.info(f"{user_id} - PeerIdInvalid") 188 | return False, "Error" 189 | except Exception: 190 | return False, "Error" 191 | 192 | 193 | async def groups_broadcast(chat_id, message, is_pin): 194 | try: 195 | m = await message.copy(chat_id=chat_id) 196 | if is_pin: 197 | try: 198 | await m.pin() 199 | except: 200 | pass 201 | return "Success" 202 | except FloodWait as e: 203 | await asyncio.sleep(e.x) 204 | return await groups_broadcast(chat_id, message) 205 | except Exception: 206 | await db.delete_chat(chat_id) 207 | logging.info(f"{chat_id}-Removed from Database.") 208 | return "Error" 209 | 210 | 211 | async def get_settings(group_id): 212 | settings = await db.get_settings(int(group_id)) 213 | return settings 214 | 215 | 216 | async def save_group_settings(group_id, key, value): 217 | current = await get_settings(group_id) 218 | current[key] = value 219 | await db.update_settings(group_id, current) 220 | 221 | 222 | def get_size(size): 223 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"] 224 | size = float(size) 225 | i = 0 226 | while size >= 1024.0 and i < len(units): 227 | i += 1 228 | size /= 1024.0 229 | return "%.2f %s" % (size, units[i]) 230 | 231 | 232 | def get_name(name): 233 | regex = re.sub(r"@\w+", "", name) 234 | return regex 235 | 236 | 237 | def list_to_str(k): 238 | if not k: 239 | return "N/A" 240 | elif len(k) == 1: 241 | return str(k[0]) 242 | else: 243 | return ", ".join(str(item) for item in k) 244 | 245 | 246 | async def get_shortlink( 247 | link, grp_id, is_second_shortener=False, is_third_shortener=False 248 | ): 249 | settings = await get_settings(grp_id) 250 | if is_third_shortener: 251 | api, site = settings["api_three"], settings["shortner_three"] 252 | else: 253 | if is_second_shortener: 254 | api, site = settings["api_two"], settings["shortner_two"] 255 | else: 256 | api, site = settings["api"], settings["shortner"] 257 | shortzy = Shortzy(api, site) 258 | try: 259 | link = await shortzy.convert(link) 260 | except Exception: 261 | link = await shortzy.get_quick_link(link) 262 | return link 263 | 264 | 265 | def get_file_id(message: "Message") -> Any: 266 | media_types = ( 267 | "audio", 268 | "document", 269 | "photo", 270 | "sticker", 271 | "animation", 272 | "video", 273 | "voice", 274 | "video_note", 275 | ) 276 | if message.media: 277 | for attr in media_types: 278 | media = getattr(message, attr, None) 279 | if media: 280 | setattr(media, "message_type", attr) 281 | return media 282 | 283 | 284 | # def get_hash(media_msg: Message) -> str: 285 | # media = get_file_id(media_msg) 286 | # return getattr(media, "file_unique_id", "")[:6] 287 | 288 | 289 | def get_status(): 290 | tz = pytz.timezone("Asia/Colombo") 291 | hour = datetime.now(tz).time().hour 292 | if 5 <= hour < 12: 293 | sts = "ɢᴏᴏᴅ ᴍᴏʀɴɪɴɢ" 294 | elif 12 <= hour < 18: 295 | sts = "ɢᴏᴏᴅ ᴀꜰᴛᴇʀɴᴏᴏɴ" 296 | else: 297 | sts = "ɢᴏᴏᴅ ᴇᴠᴇɴɪɴɢ" 298 | return sts 299 | 300 | 301 | async def is_check_admin(bot, chat_id, user_id): 302 | try: 303 | member = await bot.get_chat_member(chat_id, user_id) 304 | return member.status in [ 305 | enums.ChatMemberStatus.ADMINISTRATOR, 306 | enums.ChatMemberStatus.OWNER, 307 | ] 308 | except: 309 | return False 310 | 311 | 312 | async def get_seconds(time_string): 313 | def extract_value_and_unit(ts): 314 | value = "" 315 | unit = "" 316 | index = 0 317 | while index < len(ts) and ts[index].isdigit(): 318 | value += ts[index] 319 | index += 1 320 | unit = ts[index:].lstrip() 321 | if value: 322 | value = int(value) 323 | return value, unit 324 | 325 | value, unit = extract_value_and_unit(time_string) 326 | if unit == "s": 327 | return value 328 | elif unit == "min": 329 | return value * 60 330 | elif unit == "hour": 331 | return value * 3600 332 | elif unit == "day": 333 | return value * 86400 334 | elif unit == "month": 335 | return value * 86400 * 30 336 | elif unit == "year": 337 | return value * 86400 * 365 338 | else: 339 | return 0 340 | 341 | 342 | def get_readable_time(seconds): 343 | periods = [("days", 86400), ("hour", 3600), ("min", 60), ("sec", 1)] 344 | result = "" 345 | for period_name, period_seconds in periods: 346 | if seconds >= period_seconds: 347 | period_value, seconds = divmod(seconds, period_seconds) 348 | result += f"{int(period_value)}{period_name}" 349 | return result 350 | 351 | 352 | async def save_default_settings(id): 353 | await db.reset_group_settings(id) 354 | current = await db.get_settings(id) 355 | temp.SETTINGS.update({id: current}) 356 | -------------------------------------------------------------------------------- /plugins/channel.py: -------------------------------------------------------------------------------- 1 | # --| This code created by: Jisshu_bots & SilentXBotz |--# 2 | import re 3 | import hashlib 4 | import asyncio 5 | from info import * 6 | from utils import * 7 | from pyrogram import Client, filters 8 | from database.users_chats_db import db 9 | from database.ia_filterdb import save_file, unpack_new_file_id 10 | import aiohttp 11 | from typing import Optional 12 | from collections import defaultdict 13 | 14 | CAPTION_LANGUAGES = [ 15 | "Bhojpuri", 16 | "Hindi", 17 | "Bengali", 18 | "Tamil", 19 | "English", 20 | "Bangla", 21 | "Telugu", 22 | "Malayalam", 23 | "Kannada", 24 | "Marathi", 25 | "Punjabi", 26 | "Bengoli", 27 | "Gujrati", 28 | "Korean", 29 | "Gujarati", 30 | "Spanish", 31 | "French", 32 | "German", 33 | "Chinese", 34 | "Arabic", 35 | "Portuguese", 36 | "Russian", 37 | "Japanese", 38 | "Odia", 39 | "Assamese", 40 | "Urdu", 41 | ] 42 | 43 | UPDATE_CAPTION = """𝖭𝖤𝖶 {} 𝖠𝖣𝖣𝖤𝖣 ✅ 44 | 45 | 🎬 {} {} 46 | 🔰 Quality: {} 47 | 🎧 Audio: {} 48 | 49 | ✨ Telegram Files ✨ 50 | 51 | {} 52 | 53 |
〽️ Powered by @Jisshu_bots
""" 54 | 55 | QUALITY_CAPTION = """📦 {} : {}\n""" 56 | 57 | notified_movies = set() 58 | movie_files = defaultdict(list) 59 | POST_DELAY = 10 60 | processing_movies = set() 61 | 62 | media_filter = filters.document | filters.video | filters.audio 63 | 64 | 65 | @Client.on_message(filters.chat(CHANNELS) & media_filter) 66 | async def media(bot, message): 67 | bot_id = bot.me.id 68 | media = getattr(message, message.media.value, None) 69 | if media.mime_type in ["video/mp4", "video/x-matroska", "document/mp4"]: 70 | media.file_type = message.media.value 71 | media.caption = message.caption 72 | success_sts = await save_file(media) 73 | if success_sts == "suc" and await db.get_send_movie_update_status(bot_id): 74 | file_id, file_ref = unpack_new_file_id(media.file_id) 75 | await queue_movie_file(bot, media) 76 | 77 | 78 | async def queue_movie_file(bot, media): 79 | try: 80 | file_name = await movie_name_format(media.file_name) 81 | caption = await movie_name_format(media.caption) 82 | year_match = re.search(r"\b(19|20)\d{2}\b", caption) 83 | year = year_match.group(0) if year_match else None 84 | season_match = re.search(r"(?i)(?:s|season)0*(\d{1,2})", caption) or re.search( 85 | r"(?i)(?:s|season)0*(\d{1,2})", file_name 86 | ) 87 | if year: 88 | file_name = file_name[: file_name.find(year) + 4] 89 | elif season_match: 90 | season = season_match.group(1) 91 | file_name = file_name[: file_name.find(season) + 1] 92 | quality = await get_qualities(caption) or "HDRip" 93 | jisshuquality = await Jisshu_qualities(caption, media.file_name) or "720p" 94 | language = ( 95 | ", ".join( 96 | [lang for lang in CAPTION_LANGUAGES if lang.lower() in caption.lower()] 97 | ) 98 | or "Not Idea" 99 | ) 100 | file_size_str = format_file_size(media.file_size) 101 | file_id, file_ref = unpack_new_file_id(media.file_id) 102 | movie_files[file_name].append( 103 | { 104 | "quality": quality, 105 | "jisshuquality": jisshuquality, 106 | "file_id": file_id, 107 | "file_size": file_size_str, 108 | "caption": caption, 109 | "language": language, 110 | "year": year, 111 | } 112 | ) 113 | if file_name in processing_movies: 114 | return 115 | processing_movies.add(file_name) 116 | try: 117 | await asyncio.sleep(POST_DELAY) 118 | if file_name in movie_files: 119 | await send_movie_update(bot, file_name, movie_files[file_name]) 120 | del movie_files[file_name] 121 | finally: 122 | processing_movies.remove(file_name) 123 | except Exception as e: 124 | print(f"Error in queue_movie_file: {e}") 125 | if file_name in processing_movies: 126 | processing_movies.remove(file_name) 127 | await bot.send_message(LOG_CHANNEL, f"Failed to send movie update. Error - {e}'\n\n
If you don’t understand this error, you can ask in our support group: @Jisshu_support.
") 128 | 129 | async def send_movie_update(bot, file_name, files): 130 | try: 131 | if file_name in notified_movies: 132 | return 133 | notified_movies.add(file_name) 134 | 135 | imdb_data = await get_imdb(file_name) 136 | title = imdb_data.get("title", file_name) 137 | year_match = re.search(r"\b(19|20)\d{2}\b", file_name) 138 | year = year_match.group(0) if year_match else None 139 | poster = await fetch_movie_poster(title, files[0]["year"]) 140 | kind = imdb_data.get("kind", "").strip().upper().replace(" ", "_") if imdb_data else "" 141 | if kind == "TV_SERIES": 142 | kind = "SERIES" 143 | languages = set() 144 | for file in files: 145 | if file["language"] != "Not Idea": 146 | languages.update(file["language"].split(", ")) 147 | language = ", ".join(sorted(languages)) or "Not Idea" 148 | 149 | episode_pattern = re.compile(r"S(\d{1,2})E(\d{1,2})", re.IGNORECASE) 150 | combined_pattern = re.compile(r"S(\d{1,2})\s*E(\d{1,2})[-~]E?(\d{1,2})", re.IGNORECASE) 151 | episode_map = defaultdict(dict) 152 | combined_links = [] 153 | 154 | for file in files: 155 | caption = file["caption"] 156 | quality = file.get("jisshuquality") or file.get("quality") or "Unknown" 157 | size = file["file_size"] 158 | file_id = file['file_id'] 159 | match = episode_pattern.search(caption) 160 | combined_match = combined_pattern.search(caption) 161 | 162 | if match: 163 | ep = f"S{int(match.group(1)):02d}E{int(match.group(2)):02d}" 164 | episode_map[ep][quality] = file 165 | elif combined_match: 166 | season = f"S{int(combined_match.group(1)):02d}" 167 | ep_range = f"E{int(combined_match.group(2)):02d}-{int(combined_match.group(3)):02d}" 168 | ep = f"{season}{ep_range}" 169 | combined_links.append(f"📦 {ep} ({quality}) : {size}") 170 | elif re.search(r"complete|completed|batch|combined", caption, re.IGNORECASE): 171 | combined_links.append(f"📦 ({quality}) : {size}") 172 | 173 | quality_text = "" 174 | 175 | for ep, qualities in sorted(episode_map.items()): 176 | parts = [] 177 | for quality in sorted(qualities.keys()): 178 | f = qualities[quality] 179 | link = f"{quality}" 180 | parts.append(link) 181 | joined = " - ".join(parts) 182 | quality_text += f"📦 {ep} : {joined}\n" 183 | 184 | if combined_links: 185 | quality_text += "\nCOMBiNED ✅\n\n" 186 | quality_text += "\n".join(combined_links) + "\n" 187 | 188 | if not quality_text: 189 | quality_groups = defaultdict(list) 190 | for file in files: 191 | quality = file.get("jisshuquality") or file.get("quality") or "Unknown" 192 | quality_groups[quality].append(file) 193 | 194 | for quality, q_files in sorted(quality_groups.items()): 195 | links = [f"{f['file_size']}" for f in q_files] 196 | line = f"📦 {quality} : " + " | ".join(links) 197 | quality_text += line + "\n" 198 | 199 | image_url = poster or "https://te.legra.ph/file/88d845b4f8a024a71465d.jpg" 200 | full_caption = UPDATE_CAPTION.format(kind, title, year, files[0]['quality'], language, quality_text) 201 | 202 | movie_update_channel = await db.movies_update_channel_id() 203 | await bot.send_photo( 204 | chat_id=movie_update_channel if movie_update_channel else MOVIE_UPDATE_CHANNEL, 205 | photo=image_url, 206 | caption=full_caption, 207 | parse_mode=enums.ParseMode.HTML 208 | ) 209 | 210 | except Exception as e: 211 | print('Failed to send movie update. Error - ', e) 212 | await bot.send_message(LOG_CHANNEL, f"Failed to send movie update. Error - {e}'\n\n
If you don’t understand this error, you can ask in our support group: @Jisshu_support.
") 213 | 214 | 215 | async def get_imdb(file_name): 216 | try: 217 | formatted_name = await movie_name_format(file_name) 218 | imdb = await get_poster(formatted_name) 219 | if not imdb: 220 | return {} 221 | return { 222 | "title": imdb.get("title", formatted_name), 223 | "kind": imdb.get("kind", "Movie"), 224 | "year": imdb.get("year"), 225 | "url": imdb.get("url"), 226 | } 227 | except Exception as e: 228 | print(f"IMDB fetch error: {e}") 229 | return {} 230 | 231 | 232 | async def fetch_movie_poster(title: str, year: Optional[int] = None) -> Optional[str]: 233 | async with aiohttp.ClientSession() as session: 234 | query = title.strip().replace(" ", "+") 235 | url = f"https://jisshuapis.vercel.app/api.php?query={query}" 236 | try: 237 | async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as res: 238 | if res.status != 200: 239 | print(f"API Error: HTTP {res.status}") 240 | return None 241 | data = await res.json() 242 | 243 | for key in ["jisshu-2", "jisshu-3", "jisshu-4"]: 244 | posters = data.get(key) 245 | if posters and isinstance(posters, list) and posters: 246 | return posters[0] 247 | 248 | print(f"No Poster Found in jisshu-2/3/4 for Title: {title}") 249 | return None 250 | 251 | except aiohttp.ClientError as e: 252 | print(f"Network Error: {e}") 253 | return None 254 | except asyncio.TimeoutError: 255 | print("Request Timed Out") 256 | return None 257 | except Exception as e: 258 | print(f"Unexpected Error: {e}") 259 | return None 260 | 261 | 262 | def generate_unique_id(movie_name): 263 | return hashlib.md5(movie_name.encode("utf-8")).hexdigest()[:5] 264 | 265 | 266 | async def get_qualities(text): 267 | qualities = [ 268 | "480p", 269 | "720p", 270 | "720p HEVC", 271 | "1080p", 272 | "ORG", 273 | "org", 274 | "hdcam", 275 | "HDCAM", 276 | "HQ", 277 | "hq", 278 | "HDRip", 279 | "hdrip", 280 | "camrip", 281 | "WEB-DL", 282 | "CAMRip", 283 | "hdtc", 284 | "predvd", 285 | "DVDscr", 286 | "dvdscr", 287 | "dvdrip", 288 | "HDTC", 289 | "dvdscreen", 290 | "HDTS", 291 | "hdts", 292 | ] 293 | found_qualities = [q for q in qualities if q.lower() in text.lower()] 294 | return ", ".join(found_qualities) or "HDRip" 295 | 296 | 297 | async def Jisshu_qualities(text, file_name): 298 | qualities = ["480p", "720p", "720p HEVC", "1080p", "1080p HEVC", "2160p"] 299 | combined_text = (text.lower() + " " + file_name.lower()).strip() 300 | if "hevc" in combined_text: 301 | for quality in qualities: 302 | if "HEVC" in quality and quality.split()[0].lower() in combined_text: 303 | return quality 304 | for quality in qualities: 305 | if "HEVC" not in quality and quality.lower() in combined_text: 306 | return quality 307 | return "720p" 308 | 309 | 310 | async def movie_name_format(file_name): 311 | filename = re.sub( 312 | r"http\S+", 313 | "", 314 | re.sub(r"@\w+|#\w+", "", file_name) 315 | .replace("_", " ") 316 | .replace("[", "") 317 | .replace("]", "") 318 | .replace("(", "") 319 | .replace(")", "") 320 | .replace("{", "") 321 | .replace("}", "") 322 | .replace(".", " ") 323 | .replace("@", "") 324 | .replace(":", "") 325 | .replace(";", "") 326 | .replace("'", "") 327 | .replace("-", "") 328 | .replace("!", ""), 329 | ).strip() 330 | return filename 331 | 332 | 333 | def format_file_size(size_bytes): 334 | for unit in ["B", "KB", "MB", "GB", "TB"]: 335 | if size_bytes < 1024: 336 | return f"{size_bytes:.2f} {unit}" 337 | size_bytes /= 1024 338 | return f"{size_bytes:.2f} PB" 339 | -------------------------------------------------------------------------------- /Script.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class script(object): 4 | START_TXT = """ʜᴇʏ {}, {} 5 | 6 | ɪ ᴀᴍ ᴀ ᴘᴏᴡᴇʀꜰᴜʟ ᴀᴜᴛᴏꜰɪʟᴛᴇʀ ʙᴏᴛ. ʏᴏᴜ ᴄᴀɴ ᴜsᴇ ᴍᴇ ɪɴ ʏᴏᴜʀ ɢʀᴏᴜᴘ ɪ ᴡɪʟʟ ɢɪᴠᴇ ᴍᴏᴠɪᴇs ᴏʀ sᴇʀɪᴇs ɪɴ ʏᴏᴜʀ ɢʀᴏᴜᴘ ᴀɴᴅ ᴘᴍ !! 😍 7 |
🌿 ᴍᴀɪɴᴛᴀɪɴᴇᴅ ʙʏ : Jisshu Bots </>
""" 8 | 9 | HELP_TXT = """ᴄʟɪᴄᴋ ᴏɴ ᴛʜᴇ ʙᴜᴛᴛᴏɴꜱ ʙᴇʟᴏᴡ ᴛᴏ ɢᴇᴛ ᴅᴏᴄᴜᴍᴇɴᴛᴀᴛɪᴏɴ ᴀʙᴏᴜᴛ ꜱᴘᴇᴄɪꜰɪᴄ ᴍᴏᴅᴜʟᴇꜱ..""" 10 | 11 | TELE_TXT = """/telegraph - sᴇɴᴅ ᴍᴇ ᴘɪᴄᴛᴜʀᴇ ᴏʀ ᴠɪᴅᴇᴏ ᴜɴᴅᴇʀ (5ᴍʙ) 12 | 13 | ɴᴏᴛᴇ - ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴡᴏʀᴋ ɪɴ ʙᴏᴛʜ ɢʀᴏᴜᴘs ᴀɴᴅ ʙᴏᴛ ᴘᴍ""" 14 | 15 | FORCESUB_TEXT = """ 16 | ɪɴ ᴏʀᴅᴇʀ ᴛᴏ ɢᴇᴛ ᴛʜᴇ ᴍᴏᴠɪᴇ ʀᴇᴏ̨ᴜᴇsᴛᴇᴅ ʙʏ ʏᴏᴜ. 17 | 18 | ʏᴏᴜ ᴡɪʟʟ ʜᴀᴠᴇ ᴛᴏ ᴊᴏɪɴ ᴏᴜʀ ᴏғғɪᴄɪᴀʟ ᴄʜᴀɴɴᴇʟ. 19 | 20 | ғɪʀsᴛ, ᴄʟɪᴄᴋ ᴏɴ ᴛʜᴇ "Jᴏɪɴ ᴜᴘᴅᴀᴛᴇ Cʜᴀɴɴᴇʟ" ʙᴜᴛᴛᴏɴ, ᴛʜᴇɴ, ᴄʟɪᴄᴋ ᴏɴ ᴛʜᴇ "ʀᴇᴏ̨ᴜᴇsᴛ ᴛᴏ Jᴏɪɴ" ʙᴜᴛᴛᴏɴ. 21 | 22 | ᴀғᴛᴇʀ ᴛʜᴀᴛ, ᴛʀʏ ᴀᴄᴄᴇssɪɴɢ ᴛʜᴀᴛ ᴍᴏᴠɪᴇ ᴛʜᴇɴ, ᴄʟɪᴄᴋ ᴏɴ ᴛʜᴇ "ᴛʀʏ ᴀɢᴀɪɴ" ʙᴜᴛᴛᴏɴ. 23 | """ 24 | 25 | TTS_TXT = """ 26 | • sᴇɴᴅ /tts ᴛᴏ ᴜsᴇ ᴛʜɪs ғᴇᴀᴛᴜʀᴇ""" 27 | 28 | DISCLAIMER_TXT = """ 29 | ᴛʜɪꜱ ɪꜱ ᴀɴ ᴏᴘᴇɴ ꜱᴏᴜʀᴄᴇ ᴘʀᴏᴊᴇᴄᴛ. 30 | 31 | ᴀʟʟ ᴛʜᴇ ꜰɪʟᴇꜱ ɪɴ ᴛʜɪꜱ ʙᴏᴛ ᴀʀᴇ ꜰʀᴇᴇʟʏ ᴀᴠᴀɪʟᴀʙʟᴇ ᴏɴ ᴛʜᴇ ɪɴᴛᴇʀɴᴇᴛ ᴏʀ ᴘᴏꜱᴛᴇᴅ ʙʏ ꜱᴏᴍᴇʙᴏᴅʏ ᴇʟꜱᴇ. ᴊᴜꜱᴛ ꜰᴏʀ ᴇᴀꜱʏ ꜱᴇᴀʀᴄʜɪɴɢ ᴛʜɪꜱ ʙᴏᴛ ɪꜱ ɪɴᴅᴇxɪɴɢ ꜰɪʟᴇꜱ ᴡʜɪᴄʜ ᴀʀᴇ ᴀʟʀᴇᴀᴅʏ ᴜᴘʟᴏᴀᴅᴇᴅ ᴏɴ ᴛᴇʟᴇɢʀᴀᴍ. ᴡᴇ ʀᴇꜱᴘᴇᴄᴛ ᴀʟʟ ᴛʜᴇ ᴄᴏᴘʏʀɪɢʜᴛ ʟᴀᴡꜱ ᴀɴᴅ ᴡᴏʀᴋꜱ ɪɴ ᴄᴏᴍᴘʟɪᴀɴᴄᴇ ᴡɪᴛʜ ᴅᴍᴄᴀ ᴀɴᴅ ᴇᴜᴄᴅ. ɪꜰ ᴀɴʏᴛʜɪɴɢ ɪꜱ ᴀɢᴀɪɴꜱᴛ ʟᴀᴡ ᴘʟᴇᴀꜱᴇ ᴄᴏɴᴛᴀᴄᴛ ᴍᴇ ꜱᴏ ᴛʜᴀᴛ ɪᴛ ᴄᴀɴ ʙᴇ ʀᴇᴍᴏᴠᴇᴅ ᴀꜱᴀᴘ. ɪᴛ ɪꜱ ꜰᴏʀʙɪʙʙᴇɴ ᴛᴏ ᴅᴏᴡɴʟᴏᴀᴅ, ꜱᴛʀᴇᴀᴍ, ʀᴇᴘʀᴏᴅᴜᴄᴇ, ꜱʜᴀʀᴇ ᴏʀ ᴄᴏɴꜱᴜᴍᴇ ᴄᴏɴᴛᴇɴᴛ ᴡɪᴛʜᴏᴜᴛ ᴇxᴘʟɪᴄɪᴛ ᴘᴇʀᴍɪꜱꜱɪᴏɴ ꜰʀᴏᴍ ᴛʜᴇ ᴄᴏɴᴛᴇɴᴛ ᴄʀᴇᴀᴛᴏʀ ᴏʀ ʟᴇɢᴀʟ ᴄᴏᴘʏʀɪɢʜᴛ ʜᴏʟᴅᴇʀ. ɪꜰ ʏᴏᴜ ʙᴇʟɪᴇᴠᴇ ᴛʜɪꜱ ʙᴏᴛ ɪꜱ ᴠɪᴏʟᴀᴛɪɴɢ ʏᴏᴜʀ ɪɴᴛᴇʟʟᴇᴄᴛᴜᴀʟ ᴘʀᴏᴘᴇʀᴛʏ, ᴄᴏɴᴛᴀᴄᴛ ᴛʜᴇ ʀᴇꜱᴘᴇᴄᴛɪᴠᴇ ᴄʜᴀɴɴᴇʟꜱ ꜰᴏʀ ʀᴇᴍᴏᴠᴀʟ. ᴛʜᴇ ʙᴏᴛ ᴅᴏᴇꜱ ɴᴏᴛ ᴏᴡɴ ᴀɴʏ ᴏꜰ ᴛʜᴇꜱᴇ ᴄᴏɴᴛᴇɴᴛꜱ, ɪᴛ ᴏɴʟʏ ɪɴᴅᴇx ᴛʜᴇ ꜰɪʟᴇꜱ ꜰʀᴏᴍ ᴛᴇʟᴇɢʀᴀᴍ. 32 | 33 |
🌿 ᴍᴀɪɴᴛᴀɪɴᴇᴅ ʙʏ : Jisshu Bots </>
""" 34 | 35 | ABOUT_TEXT = """
‣ ᴍʏ ɴᴀᴍᴇ : Jisshu filter bot 36 | ‣ ᴄʀᴇᴀᴛᴏʀ : Jisshu Bots </> 37 | ‣ ʟɪʙʀᴀʀʏ : ᴘʏʀᴏɢʀᴀᴍ 38 | ‣ ʟᴀɴɢᴜᴀɢᴇ : ᴘʏᴛʜᴏɴ 39 | ‣ ᴅᴀᴛᴀ ʙᴀsᴇ : ᴍᴏɴɢᴏ ᴅʙ 40 | ‣ ʜᴏsᴛᴇᴅ ᴏɴ : ᴡᴇʙ 41 | ‣ ʙᴜɪʟᴅ sᴛᴀᴛᴜs : V-4.1 [sᴛᴀʙʟᴇ]
""" 42 | 43 | SUPPORT_GRP_MOVIE_TEXT = """ʜᴇʏ {} 44 | 45 | ɪ ғᴏᴜɴᴅ {} ʀᴇsᴜʟᴛs 🎁, 46 | ʙᴜᴛ ɪ ᴄᴀɴ'ᴛ sᴇɴᴅ ʜᴇʀᴇ 🤞🏻 47 | ᴘʟᴇᴀsᴇ ᴊᴏɪɴ ᴏᴜʀ ʀᴇǫᴜᴇsᴛ ɢʀᴏᴜᴘ ᴛᴏ ɢᴇᴛ ✨""" 48 | 49 | CHANNELS = """ 50 | ᴏᴜʀ ᴀʟʟ ɢʀᴏᴜᴘꜱ ᴀɴᴅ ᴄʜᴀɴɴᴇʟꜱ 51 | 52 | ▫ ᴀʟʟ ʟᴀᴛᴇꜱᴛ ᴀɴᴅ ᴏʟᴅ ᴍᴏᴠɪᴇꜱ & ꜱᴇʀɪᴇꜱ. 53 | ▫ ᴀʟʟ ʟᴀɴɢᴜᴀɢᴇꜱ ᴍᴏᴠɪᴇꜱ ᴀᴠᴀɪʟᴀʙʟᴇ. 54 | ▫ ᴀʟᴡᴀʏꜱ ᴀᴅᴍɪɴ ꜱᴜᴘᴘᴏʀᴛ. 55 | ▫ 𝟸𝟺x𝟽 ꜱᴇʀᴠɪᴄᴇꜱ ᴀᴠᴀɪʟᴀʙʟᴇ.""" 56 | 57 | JISSHUPREMIUM_TXT = """ 58 |
ᴛᴏ ᴇxᴘᴇʀɪᴇɴᴄᴇ ᴀᴅꜱ ꜰʀᴇᴇ ꜱᴇʀᴠɪᴄᴇ ʏᴏᴜ ᴄᴀɴ ʙᴜʏ ᴏᴜʀ ᴘʀᴇᴍɪᴜᴍ ꜱᴇʀᴠɪᴄᴇ ᴏʀ ʏᴏᴜ ᴄᴀɴ ꜱʜᴀʀᴇ ᴏᴜʀ ʙᴏᴛ ᴡɪᴛʜ ʏᴏᴜʀ ꜰʀɪᴇɴᴅꜱ ᴛᴏ ɢᴇᴛ ᴘʀᴇᴍɪᴜᴍ.
""" 59 | 60 | LOGO = """ 61 | sᴛᴀʀᴛɪɴɢ.... 62 | sᴜᴄᴄᴇssғᴜʟʟʏ sᴛᴀʀᴛᴇᴅ ᴛʜᴇ ʙᴏᴛ""" 63 | 64 | RESTART_TXT = """ 65 | Bᴏᴛ Rᴇsᴛᴀʀᴛᴇᴅ ! 66 | >> {} 67 | 68 | 📅 Dᴀᴛᴇ : {} 69 | ⏰ Tɪᴍᴇ : {} 70 | 🌐 Tɪᴍᴇᴢᴏɴᴇ : Asia/Kolkata 71 | 🛠️ Bᴜɪʟᴅ Sᴛᴀᴛᴜs: v-3.1.2 [ Sᴛᴀʙʟᴇ ] 72 | 73 | If there is an error, ask in the support group @Jisshu_support""" 74 | 75 | STATUS_TXT = """♻️ ʙᴏᴛ ᴅᴀᴛᴀʙᴀsᴇ 76 | 77 | » ᴛᴏᴛᴀʟ ᴜsᴇʀs - {} 78 | » ᴛᴏᴛᴀʟ ɢʀᴏᴜᴘs - {} 79 | » ᴜsᴇᴅ sᴛᴏʀᴀɢᴇ - {} / {} 80 | 81 | 📁 ꜰɪʟᴇs ᴅᴀᴛᴀʙᴀsᴇ 82 | 83 | » ᴛᴏᴛᴀʟ ꜰɪʟᴇs - {} 84 | » ᴜsᴇᴅ sᴛᴏʀᴀɢᴇ - {} / {} 85 | 86 | 🤖 ʙᴏᴛ ᴅᴇᴛᴀɪʟs 87 | 88 | » ᴜᴘᴛɪᴍᴇ - {} 89 | » ʀᴀᴍ - {}% 90 | » ᴄᴘᴜ - {}%""" 91 | 92 | NEW_USER_TXT = """#New_User {} 93 | 94 | ≈ ɪᴅ:- {} 95 | ≈ ɴᴀᴍᴇ:- {}""" 96 | 97 | NEW_GROUP_TXT = """#New_Group {} 98 | 99 | Group name - {} 100 | Id - {} 101 | Group username - @{} 102 | Group link - {} 103 | Total members - {} 104 | User - {}""" 105 | 106 | REQUEST_TXT = """📜 ᴜꜱᴇʀ - {} 107 | 📇 ɪᴅ - {} 108 | 109 | 🎁 ʀᴇǫᴜᴇꜱᴛ ᴍꜱɢ - {}""" 110 | 111 | IMDB_TEMPLATE_TXT = """ 112 | ʜᴇʏ {message.from_user.mention}, ʜᴇʀᴇ ɪꜱ ᴛʜᴇ ʀᴇꜱᴜʟᴛꜱ ꜰᴏʀ ʏᴏᴜʀ ǫᴜᴇʀʏ {search}. 113 | 114 | 🍿 Title: {title} 115 | 🎃 Genres: {genres} 116 | 📆 Year: {release_date} 117 | ⭐ Rating: {rating} / 10 118 | """ 119 | 120 | FILE_CAPTION = """{file_name}""" 121 | 122 | ALRT_TXT = """ᴡʜᴀᴛ ᴀʀᴇ ʏᴏᴜ sᴇᴀʀᴄʜɪɴɢ !?""" 123 | 124 | OLD_ALRT_TXT = """ʏᴏᴜ ᴀʀᴇ ᴜsɪɴɢ ᴍʏ ᴏʟᴅ ᴍᴇssᴀɢᴇs..sᴇɴᴅ ᴀ ɴᴇᴡ ʀᴇǫᴜᴇsᴛ..""" 125 | 126 | NO_RESULT_TXT = """ᴛʜɪs ᴍᴇssᴀɢᴇ ɪs ɴᴏᴛ ʀᴇʟᴇᴀsᴇᴅ ᴏʀ ᴀᴅᴅᴇᴅ ɪɴ ᴍʏ ᴅᴀᴛᴀʙᴀsᴇ 🙄""" 127 | 128 | I_CUDNT = """🤧 𝗛𝗲𝗹𝗹𝗼 {} 129 | 130 | 𝗜 𝗰𝗼𝘂𝗹𝗱𝗻'𝘁 𝗳𝗶𝗻𝗱 𝗮𝗻𝘆 𝗺𝗼𝘃𝗶𝗲 𝗼𝗿 𝘀𝗲𝗿𝗶𝗲𝘀 𝗶𝗻 𝘁𝗵𝗮𝘁 𝗻𝗮𝗺𝗲.. 😐""" 131 | 132 | I_CUD_NT = """😑 𝗛𝗲𝗹𝗹𝗼 {} 133 | 134 | 𝗜 𝗰𝗼𝘂𝗹𝗱𝗻'𝘁 𝗳𝗶𝗻𝗱 𝗮𝗻𝘆𝘁𝗵𝗶𝗻𝗴 𝗿𝗲𝗹𝗮𝘁𝗲𝗱 𝘁𝗼 𝘁𝗵𝗮𝘁 😞... 𝗰𝗵𝗲𝗰𝗸 𝘆𝗼𝘂𝗿 𝘀𝗽𝗲𝗹𝗹𝗶𝗻𝗴.""" 135 | 136 | CUDNT_FND = """🤧 𝗛𝗲𝗹𝗹𝗼 {} 137 | 138 | 𝗜 𝗰𝗼𝘂𝗹𝗱𝗻'𝘁 𝗳𝗶𝗻𝗱 𝗮𝗻𝘆𝘁𝗵𝗶𝗻𝗴 𝗿𝗲𝗹𝗮𝘁𝗲𝗱 𝘁𝗼 𝘁𝗵𝗮𝘁 𝗱𝗶𝗱 𝘆𝗼𝘂 𝗺𝗲𝗮𝗻 𝗮𝗻𝘆 𝗼𝗻𝗲 𝗼𝗳 𝘁𝗵𝗲𝘀𝗲 ?? 👇""" 139 | 140 | FONT_TXT = """ʏᴏᴜ ᴄᴀɴ ᴜsᴇ ᴛʜɪs ᴍᴏᴅᴇ ᴛᴏ ᴄʜᴀɴɢᴇ ʏᴏᴜʀ ꜰᴏɴᴛs sᴛʏʟᴇ, ᴊᴜsᴛ sᴇɴᴅ ᴍᴇ ʟɪᴋᴇ ᴛʜɪs ꜰᴏʀᴍᴀᴛ 141 | 142 | /font hi how are you""" 143 | 144 | SPECIAL_TXT = """ Here Is My Some Special Features Broh ! """ 145 | 146 | EARN_TEXT = """
💸 ʜᴏᴡ ᴛᴏ ᴇᴀʀɴ ᴍᴏɴᴇʏ ʙʏ ᴛʜɪs ʙᴏᴛ -
147 | 148 | 1:- ʏᴏᴜ ᴍᴜꜱᴛ ʜᴀᴠᴇ ᴀᴛʟᴇᴀꜱᴛ ᴏɴᴇ ɢʀᴏᴜᴘ ᴡɪᴛʜ ᴍɪɴɪᴍᴜᴍ 100 ᴍᴇᴍʙᴇʀꜱ. 149 | 150 | 2:- ᴍᴀᴋᴇ ᴛʜɪs ᴀᴅᴍɪɴ ɪɴ ʏᴏᴜʀ ɢʀᴏᴜᴘ. 151 | 152 | 3:- ᴄʀᴇᴀᴛᴇ ᴀᴄᴄᴏᴜɴᴛ ᴏɴ ᴀɴʏ sʜᴏʀᴛɴᴇʀ ʟɪᴋᴇ ʏᴏᴜ ᴄᴀɴ ᴀʟsᴏ ᴜsᴇ ᴛʜɪs ʙᴇsᴛ sʜᴏʀᴛɴᴇʀ Best Shortner. 153 | 154 | 4:- ᴛʜᴇɴ sᴇᴛ ʏᴏᴜʀ sʜᴏʀᴛɴᴇʀ ᴅᴇᴛᴀɪʟs ʙʏ ᴛʜɪs ꜰᴏʀᴍᴀᴛ 👇 155 | 156 | /set_verify linkmonetizer.in fcee6bbc628cfc61229a2d808e1b0ee3315a0f5e 157 | 158 | /set_verify_2 linkmonetizer.in fcee6bbc628cfc61229a2d808e1b0ee3315a0f5e 159 | 160 | /set_verify_3 linkmonetizer.in fcee6bbc628cfc61229a2d808e1b0ee3315a0f5e 161 | 162 | /set_tutorial https://t.me/Jisshu_developer 163 | 164 | /set_tutorial_2 https://t.me/Jisshu_developer 165 | 166 | /set_tutorial_3 https://t.me/Jisshu_developer 167 | 168 | /set_time_2 300 169 | 170 | /set_time_3 300 171 | 172 | /set_fsub -100******* 173 | 174 | /set_log -100******* 175 | 176 | ʏᴏᴜ ᴄᴀɴ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀʟʟ ᴅᴇᴛᴀɪʟs ʙʏ /details ᴄᴏᴍᴍᴀɴᴅ 177 | 178 | 💯 ɴᴏᴛᴇ - ᴛʜɪs ʙᴏᴛ ɪs ꜰʀᴇᴇ ᴛᴏ ᴀʟʟ, ʏᴏᴜ ᴄᴀɴ ᴜsᴇ ᴛʜɪs ʙᴏᴛ ɪɴ ʏᴏᴜʀ ɢʀᴏᴜᴘs ᴀɴᴅ ᴇᴀʀɴ ᴜɴʟɪᴍɪᴛᴇᴅ ᴍᴏɴᴇʏ.
""" 179 | 180 | VERIFICATION_TEXT = """👋 ʜᴇʏ {} {}, 181 | 182 | 📌 ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪғɪᴇᴅ ᴛᴏᴅᴀʏ, ᴘʟᴇᴀꜱᴇ ᴄʟɪᴄᴋ ᴏɴ ᴠᴇʀɪғʏ & ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇꜱꜱ ғᴏʀ ᴛɪʟʟ ɴᴇxᴛ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ 183 | 184 | #ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ:- 1/3 ✓ 185 | 186 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ 😊 187 | 188 | 💶 sᴇɴᴅ /plan ᴛᴏ ʙᴜʏ sᴜʙsᴄʀɪᴘᴛɪᴏɴ""" 189 | 190 | VERIFY_COMPLETE_TEXT = """👋 ʜᴇʏ {}, 191 | 192 | ʏᴏᴜ ʜᴀᴠᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ᴛʜᴇ 1st ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ ✓ 193 | 194 | ɴᴏᴡ ʏᴏᴜ ʜᴀᴠᴇ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ɴᴇxᴛ {}""" 195 | 196 | SECOND_VERIFICATION_TEXT = """👋 ʜᴇʏ {} {}, 197 | 198 | 📌 ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪꜰɪᴇᴅ, ᴛᴀᴘ ᴏɴ ᴛʜᴇ ᴠᴇʀɪꜰʏ ʟɪɴᴋ ᴀɴᴅ ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ᴛɪʟʟ ɴᴇxᴛ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ 199 | 200 | #ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ:- 2/3 201 | 202 | ɪғ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇꜱ ᴡɪᴛʜᴏᴜᴛ ᴀɴʏ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴꜱ ᴛʜᴇɴ ʙᴜʏ ʙᴏᴛ ꜱᴜʙꜱᴄʀɪᴘᴛɪᴏɴ 😊 203 | 204 | 💶 sᴇɴᴅ /plan ᴛᴏ ʙᴜʏ sᴜʙsᴄʀɪᴘᴛɪᴏɴ""" 205 | 206 | SECOND_VERIFY_COMPLETE_TEXT = """👋 ʜᴇʏ {}, 207 | 208 | ʏᴏᴜ ʜᴀᴠᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ᴛʜᴇ 2nd ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ ✓ 209 | 210 | ɴᴏᴡ ʏᴏᴜ ʜᴀᴠᴇ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ɴᴇxᴛ {}""" 211 | 212 | THIRDT_VERIFICATION_TEXT = """👋 ʜᴇʏ {}, 213 | 214 | 📌 ʏᴏᴜ ᴀʀᴇ ɴᴏᴛ ᴠᴇʀɪꜰɪᴇᴅ ᴛᴏᴅᴀʏ, ᴛᴀᴘ ᴏɴ ᴛʜᴇ ᴠᴇʀɪꜰʏ ʟɪɴᴋ & ɢᴇᴛ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ɴᴇxᴛ ꜰᴜʟʟ ᴅᴀʏ. 215 | 216 | #ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ:- 3/3 217 | 218 | ɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴅɪʀᴇᴄᴛ ꜰɪʟᴇs ᴛʜᴇɴ ʏᴏᴜ ᴄᴀɴ ᴛᴀᴋᴇ ᴘʀᴇᴍɪᴜᴍ sᴇʀᴠɪᴄᴇ (ɴᴏ ɴᴇᴇᴅ ᴛᴏ ᴠᴇʀɪꜰʏ)""" 219 | 220 | THIRDT_VERIFY_COMPLETE_TEXT = """👋 ʜᴇʏ {}, 221 | 222 | ʏᴏᴜ ʜᴀᴠᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ᴛʜᴇ 3rd ᴠᴇʀɪꜰɪᴄᴀᴛɪᴏɴ ✓ 223 | 224 | ɴᴏᴡ ʏᴏᴜ ʜᴀᴠᴇ ᴜɴʟɪᴍɪᴛᴇᴅ ᴀᴄᴄᴇss ꜰᴏʀ ɴᴇxᴛ ꜰᴜʟʟ ᴅᴀʏ """ 225 | 226 | VERIFIED_LOG_TEXT = """☄ є∂ιтн ᴜsᴇʀ ᴠᴇʀɪꜰɪᴇᴅ sᴜᴄᴄᴇssꜰᴜʟʟʏ ☄ 227 | 228 | ⚡️ ɴᴀᴍᴇ:- {} [ {} ] 229 | 📆 ᴅᴀᴛᴇ:- {} 230 | 231 | #edith_verified_{}_completed""" 232 | 233 | MOVIES_UPDATE_TXT = """#𝑵𝒆𝒘_𝑭𝒊𝒍𝒆_𝑨𝒅𝒅𝒆𝒅 ✅ 234 | **🍿 Title:** {title} 235 | **🎃 Genres:** {genres} 236 | **📆 Year:** {year} 237 | **⭐ Rating:** {rating} / 10 238 | """ 239 | 240 | PREPLANS_TXT = """👋 ʜᴇʏ {}, 241 | 242 |
🎁 ᴘʀᴇᴍɪᴜᴍ ғᴇᴀᴛᴜʀᴇ ʙᴇɴɪꜰɪᴛꜱ:
243 | 244 | ❏ ɴᴏ ɴᴇᴇᴅ ᴛᴏ ᴏᴘᴇɴ ʟɪɴᴋꜱ 245 | ❏ ɢᴇᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇs 246 | ❏ ᴀᴅ-ғʀᴇᴇ ᴇxᴘᴇʀɪᴇɴᴄᴇ 247 | ❏ ʜɪɢʜ-sᴘᴇᴇᴅ ᴅᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ 248 | ❏ ᴍᴜʟᴛɪ-ᴘʟᴀʏᴇʀ sᴛʀᴇᴀᴍɪɴɢ ʟɪɴᴋs 249 | ❏ ᴜɴʟɪᴍɪᴛᴇᴅ ᴍᴏᴠɪᴇs ᴀɴᴅ sᴇʀɪᴇs 250 | ❏ ꜰᴜʟʟ ᴀᴅᴍɪɴ sᴜᴘᴘᴏʀᴛ 251 | ❏ ʀᴇǫᴜᴇsᴛ ᴡɪʟʟ ʙᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ɪɴ 𝟷ʜ [ ɪꜰ ᴀᴠᴀɪʟᴀʙʟᴇ ] 252 | 253 | ⛽️ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀᴄᴛɪᴠᴇ ᴘʟᴀɴ: /myplan 254 |
""" 255 | 256 | PREPLANSS_TXT = """👋 ʜᴇʏ {} 257 | 258 |
🎁 ᴘʀᴇᴍɪᴜᴍ ғᴇᴀᴛᴜʀᴇ ʙᴇɴɪꜰɪᴛꜱ:
259 | 260 | ❏ ɴᴏ ɴᴇᴇᴅ ᴛᴏ ᴏᴘᴇɴ ʟɪɴᴋꜱ 261 | ❏ ɢᴇᴛ ᴅɪʀᴇᴄᴛ ғɪʟᴇs 262 | ❏ ᴀᴅ-ғʀᴇᴇ ᴇxᴘᴇʀɪᴇɴᴄᴇ 263 | ❏ ʜɪɢʜ-sᴘᴇᴇᴅ ᴅᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ 264 | ❏ ᴍᴜʟᴛɪ-ᴘʟᴀʏᴇʀ sᴛʀᴇᴀᴍɪɴɢ ʟɪɴᴋs 265 | ❏ ᴜɴʟɪᴍɪᴛᴇᴅ ᴍᴏᴠɪᴇs ᴀɴᴅ sᴇʀɪᴇs 266 | ❏ ꜰᴜʟʟ ᴀᴅᴍɪɴ sᴜᴘᴘᴏʀᴛ 267 | ❏ ʀᴇǫᴜᴇsᴛ ᴡɪʟʟ ʙᴇ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ɪɴ 𝟷ʜ [ ɪꜰ ᴀᴠᴀɪʟᴀʙʟᴇ ] 268 | 269 | ⛽️ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀᴄᴛɪᴠᴇ ᴘʟᴀɴ: /myplan 270 |
""" 271 | 272 | OTHER_TXT = """👋 ʜᴇʏ {}, 273 | 274 | 🎁 ᴏᴛʜᴇʀ ᴘʟᴀɴ 275 | ⏰ ᴄᴜꜱᴛᴏᴍɪꜱᴇᴅ ᴅᴀʏꜱ 276 | 💸 ᴀᴄᴄᴏʀᴅɪɴɢ ᴛᴏ ᴅᴀʏꜱ ʏᴏᴜ ᴄʜᴏᴏꜱᴇ 277 | 278 | 🏆 ɪꜰ ʏᴏᴜ ᴡᴀɴᴛ ᴀ ɴᴇᴡ ᴘʟᴀɴ ᴀᴘᴀʀᴛ ꜰʀᴏᴍ ᴛʜᴇ ɢɪᴠᴇɴ ᴘʟᴀɴ, ᴛʜᴇɴ ʏᴏᴜ ᴄᴀɴ ᴛᴀʟᴋ ᴛᴏ ᴏᴜʀ ᴏᴡɴᴇʀ ᴅɪʀᴇᴄᴛʟʏ ʙʏ ᴄʟɪᴄᴋɪɴɢ ᴏɴ ᴛʜᴇ ᴄᴏɴᴛᴀᴄᴛ ʙᴜᴛᴛᴏɴ ɢɪᴠᴇɴ ʙᴇʟᴏᴡ. 279 | 280 | 👨‍💻 ᴄᴏɴᴛᴀᴄᴛ ᴛʜᴇ ᴏᴡɴᴇʀ ᴛᴏ ɢᴇᴛ ʏᴏᴜʀ ᴏᴛʜᴇʀ ᴘʟᴀɴ. 281 | 282 | ➛ ᴜꜱᴇ /plan ᴛᴏ ꜱᴇᴇ ᴀʟʟ ᴏᴜʀ ᴘʟᴀɴꜱ ᴀᴛ ᴏɴᴄᴇ. 283 | ➛ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀᴄᴛɪᴠᴇ ᴘʟᴀɴ ʙʏ ᴜꜱɪɴɢ : /myplan""" 284 | 285 | FREE_TXT = """👋 ʜᴇʏ {} 286 | 287 |
🎖️ᴀᴠᴀɪʟᴀʙʟᴇ ᴘʀᴇᴍɪᴜᴍ ᴘʟᴀɴꜱ :
288 | 289 | ❏ 𝟶𝟷𝟻₹ ➠ 𝟶𝟷 ᴡᴇᴇᴋꜱ 290 | ❏ 𝟶𝟹𝟿₹ ➠ 𝟶𝟷 ᴍᴏɴᴛʜ 291 | ❏ 𝟶𝟽𝟻₹ ➠ 𝟶𝟸 ᴍᴏɴᴛʜ 292 | ❏ 𝟷𝟷𝟶₹ ➠ 𝟶𝟹 ᴍᴏɴᴛʜ 293 | ❏ 𝟷𝟿𝟿₹ ➠ 𝟶𝟼 ᴍᴏɴᴛʜ 294 | ❏ 𝟹𝟼𝟶₹ ➠ 𝟷𝟸 ᴍᴏɴᴛʜ 295 | 296 | 🆔 ᴜᴘɪ ɪᴅ ➩ jishan@fam [ᴛᴀᴘ ᴛᴏ ᴄᴏᴘʏ] 297 | 298 | ⛽️ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀᴄᴛɪᴠᴇ ᴘʟᴀɴ: /myplan 299 | 300 | 🏷️ ᴘʀᴇᴍɪᴜᴍ ᴘʀᴏᴏꜰ 301 | 302 | ‼️ ᴍᴜsᴛ sᴇɴᴅ sᴄʀᴇᴇɴsʜᴏᴛ ᴀғᴛᴇʀ ᴘᴀʏᴍᴇɴᴛ. 303 | ‼️ ɢɪᴠᴇ ᴜꜱ ꜱᴏᴍᴇᴛɪᴍᴇ ᴛᴏ ᴀᴅᴅ ʏᴏᴜ ɪɴ ᴘʀᴇᴍɪᴜᴍ ʟɪꜱᴛ. 304 |
""" 305 | 306 | ADMIN_CMD_TXT_TO1 = """
307 | --------------Index File-------------- 308 | ➩ /index - Index all files 309 | --------------Leave Link-------------- 310 | ➩ /leave {group ID} - Leave the specified group 311 | -------------Send Message------------- 312 | ➩ /send {user name} - Use this command as a reply to any message 313 | ----------------Ban User--------------- 314 | ➩ /ban {user name} - Ban user 315 | ➩ /unban {user name} - Unban user 316 | --------------Broadcast-------------- 317 | ➩ /broadcast - Broadcast a message to all users 318 | ➩ /grp_broadcast - Broadcast a message to all connected groups 319 | ------------------------------------------- 320 | /ads - IB 321 |
""" 322 | 323 | ADMIN_CMD_TXT = """
324 | -------------User Premium------------ 325 | ➩ /add_premium {user ID} {Times} - Add a premium user 326 | ➩ /remove_premium {user ID} - Remove a premium user 327 | ➩ /add_redeem - Generate a redeem code 328 | ➩ /premium_users - List all premium users 329 | ➩ /refresh - Refresh free trial for users 330 | -------------Update Channel---------- 331 | ➩ /set_muc {channel ID} - Set the movies update channel 332 | --------------PM Search-------------- 333 | ➩ /pm_search_on - Enable PM search 334 | ➩ /pm_search_off - Disable PM search 335 | --------------Index File-------------- 336 | ➩ /index - Index all files 337 | --------------Leave Link-------------- 338 | ➩ /leave {group ID} - Leave the specified group 339 | --------------Broadcast-------------- 340 | ➩ /broadcast - /grp_broadcast 341 | --------------Set Ads---------------- 342 | ➩ /set_ads {ads name}#{Times}#{photo URL} - Explain 343 | ➩ /del_ads - Delete ads 344 | -------------Top Trending------------ 345 | ➩ /setlist {Mirzapur, Money Heist} - Explain 346 | ➩ /clearlist - Clear all lists 347 |
""" 348 | 349 | GROUP_TEXT = """
350 | --------------Set Verify------------- 351 | /set_verify {{website link}} {{website api}} 352 | /set_verify_2 {{website link}} {{website api}} 353 | /set_verify_3 {{website link}} {{website api}} 354 | -------------Set Verify Time----------- 355 | /set_time_2 {{seconds}} Sᴇᴛ ᴛʜᴇ sᴇᴄᴏɴᴅ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ ᴛɪᴍᴇ 356 | /set_time_3 {{seconds}} Sᴇᴛ ᴛʜᴇ ᴛʜɪʀᴅ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ ᴛɪᴍᴇ 357 | --------------Verify On Off------------ 358 | /verifyoff - off verification Cᴏɴᴛᴀᴄᴛ ᴛʜᴇ ʙᴏᴛ ᴀᴅᴍɪɴ ғᴏʀ ᴀ ᴠᴇʀɪғʏ.ᴏғғ 359 | /verifyon - on verification 360 | ------------Set File Caption----------- 361 | /set_caption - set coustom file caption 362 | -----------Set Imdb Template----------- 363 | /set_template - set IMDb template Example 364 | --------------Set Tutorial------------- 365 | /set_tutorial - set verification tutorial 366 | -------------Set Log Channel----------- 367 | --> ᴀᴅᴅ ʟᴏɢ ᴄʜᴀɴɴᴇʟ ʙʏ ᴛʜɪs ꜰᴏʀᴍᴀᴛ & ᴍᴀᴋᴇ sᴜʀᴇ ʙᴏᴛ ɪs ᴀᴅᴍɪɴ ɪɴ ʏᴏᴜʀ ʟᴏɢ ᴄʜᴀɴɴᴇʟ 👇 368 | 369 | /set_log {{log channel id}} 370 | --------------------------------------- 371 | ʏᴏᴜ ᴄᴀɴ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀʟʟ ᴅᴇᴛᴀɪʟs 372 | ʙʏ /details ᴄᴏᴍᴍᴀɴᴅ 373 |
374 | Aᴅᴅ ᴍᴇ ᴛᴏ ʏᴏᴜʀ ɢʀᴏᴜᴘ ᴀɴᴅ ᴍᴀᴋᴇ ᴍᴇ ᴀᴅᴍɪɴ ᴀɴᴅ ᴜsᴇ ᴀʟʟ ғᴇᴀᴛᴜʀᴇs😇
""" 375 | 376 | ALLADMINCMD_TXT = """
377 | -------------User Premium------------ 378 | ➩ /add_premium {user ID} {Times} - Add a premium user 379 | ➩ /remove_premium {user ID} - Remove a premium user 380 | ➩ /add_redeem - Generate a redeem code 381 | ➩ /premium_users - List all premium users 382 | ➩ /refresh - Refresh free trial for users 383 | -------------Update Channel---------- 384 | ➩ /set_muc {channel ID} - Set the movies update channel 385 | --------------PM Search-------------- 386 | ➩ /pm_search_on - Enable PM search 387 | ➩ /pm_search_off - Disable PM search 388 | --------------Verify ID-------------- 389 | ➩ /verifyon - on verification 390 | ➩ /verifyoff - off verification only for group 391 | --------------Set Ads---------------- 392 | ➩ /set_ads {ads name}#{Times}#{photo URL} - Explain 393 | ➩ /del_ads - Delete ads 394 | -------------Top Trending------------ 395 | ➩ /setlist {Mirzapur, Money Heist} - Explain 396 | ➩ /clearlist - Clear all lists 397 | --------------Index File-------------- 398 | ➩ /index - Index all files 399 | --------------Leave Link-------------- 400 | ➩ /leave {group ID} - Leave the specified group 401 | -------------Send Message------------- 402 | ➩ /send {user-name} - Use this command as a reply to any message 403 | ----------------Ban User--------------- 404 | ➩ /ban {user-name} - Ban user 405 | ➩ /unban {user-name} - Unban user 406 | --------------Broadcast-------------- 407 | ➩ /broadcast - Broadcast a message to all users 408 | ➩ /grp_broadcast - Broadcast a message to all connected groups 409 | ------------------------------------------- 410 | /ads - to set advertisement 411 | /reset_group - reset to default 412 | /movie_update_off - update off 413 | /movie_update_on - Movie Update on
""" 414 | 415 | SOURCE_TXT = """ 416 | ꜱᴏᴜʀᴄᴇ ᴄᴏᴅᴇ ʜᴇʀᴇ ◉› :
<Click Here>
417 | 418 | ᴍᴀɪɴᴛᴀɪɴᴇᴅ ʙʏ : @jisshu_bots 419 |
""" 420 | GROUP_C_TEXT = """
421 | --------------Set Verify------------- 422 | /set_verify {website link} {website api} 423 | /set_verify_2 {website link} {website api} 424 | /set_verify_3 {website link} {website api} 425 | -------------Set Verify Time----------- 426 | /set_time_2 {seconds} Sᴇᴛ ᴛʜᴇ sᴇᴄᴏɴᴅ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ ᴛɪᴍᴇ 427 | /set_time_3 {seconds} Sᴇᴛ ᴛʜᴇ ᴛʜɪʀᴅ ᴠᴇʀɪғɪᴄᴀᴛɪᴏɴ ᴛɪᴍᴇ 428 | --------------Verify On Off------------ 429 | /verifyoff {verify.off code} - off verification Cᴏɴᴛᴀᴄᴛ ᴛʜᴇ ʙᴏᴛ ᴀᴅᴍɪɴ ғᴏʀ ᴀ ᴠᴇʀɪғʏ.ᴏғғ ᴄᴏᴅᴇ 430 | /verifyon - on verification 431 | ------------Set File Caption----------- 432 | /set_caption - set coustom file caption 433 | -----------Set Imdb Template----------- 434 | /set_template - set IMDb template Example 435 | --------------Set Tutorial------------- 436 | /set_tutorial {tutorial link} - set 1 verification tutorial 437 | /set_tutorial_2 {tutorial link} - set 2 verification tutorial 438 | /set_tutorial_3 {tutorial link} - set 3 verification tutorial 439 | -------------Set Log Channel----------- 440 | --> ᴀᴅᴅ ʟᴏɢ ᴄʜᴀɴɴᴇʟ ʙʏ ᴛʜɪs ꜰᴏʀᴍᴀᴛ & ᴍᴀᴋᴇ sᴜʀᴇ ʙᴏᴛ ɪs ᴀᴅᴍɪɴ ɪɴ ʏᴏᴜʀ ʟᴏɢ ᴄʜᴀɴɴᴇʟ 👇 441 | 442 | /set_log {log channel id} 443 | --------------------------------------- 444 | ʏᴏᴜ ᴄᴀɴ ᴄʜᴇᴄᴋ ʏᴏᴜʀ ᴀʟʟ ᴅᴇᴛᴀɪʟs 445 | ʙʏ /details ᴄᴏᴍᴍᴀɴᴅ 446 |
447 | Iғ ʏᴏᴜ ʜᴀᴠᴇ ᴀɴʏ ᴅᴏᴜʙᴛs ᴘʟᴇᴀsᴇ ᴄᴏɴᴛᴀᴄᴛ ᴍʏ Z I Ƨ Ή Λ П ♡
""" 448 | -------------------------------------------------------------------------------- /database/users_chats_db.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import pytz 3 | from motor.motor_asyncio import AsyncIOMotorClient 4 | 5 | # from info import SETTINGS, IS_PM_SEARCH, IS_SEND_MOVIE_UPDATE, PREMIUM_POINT,REF_PREMIUM,IS_VERIFY, SHORTENER_WEBSITE3, SHORTENER_API3, THREE_VERIFY_GAP, LINK_MODE, FILE_CAPTION, TUTORIAL, DATABASE_NAME, DATABASE_URI, IMDB, IMDB_TEMPLATE, PROTECT_CONTENT, AUTO_DELETE, SPELL_CHECK, AUTO_FILTER, LOG_VR_CHANNEL, SHORTENER_WEBSITE, SHORTENER_API, SHORTENER_WEBSITE2, SHORTENER_API2, TWO_VERIFY_GAP 6 | # from utils import get_seconds 7 | from info import * 8 | 9 | client = AsyncIOMotorClient(DATABASE_URI) 10 | mydb = client[DATABASE_NAME] 11 | 12 | 13 | class Database: 14 | def __init__(self): 15 | self.col = mydb.users 16 | self.grp = mydb.groups 17 | self.misc = mydb.misc 18 | self.verify_id = mydb.verify_id 19 | self.users = mydb.uersz 20 | self.req = mydb.requests 21 | self.mGrp = mydb.mGrp 22 | self.pmMode = mydb.pmMode 23 | self.jisshu_ads_link = mydb.jisshu_ads_link 24 | self.movies_update_channel = mydb.movies_update_channel 25 | self.botcol = mydb.botcol 26 | 27 | default = { 28 | "spell_check": SPELL_CHECK, 29 | "auto_filter": AUTO_FILTER, 30 | "file_secure": PROTECT_CONTENT, 31 | "auto_delete": AUTO_DELETE, 32 | "template": IMDB_TEMPLATE, 33 | "caption": FILE_CAPTION, 34 | "tutorial": TUTORIAL, 35 | "tutorial_2": TUTORIAL_2, 36 | "tutorial_3": TUTORIAL_3, 37 | "shortner": SHORTENER_WEBSITE, 38 | "api": SHORTENER_API, 39 | "shortner_two": SHORTENER_WEBSITE2, 40 | "api_two": SHORTENER_API2, 41 | "log": LOG_VR_CHANNEL, 42 | "imdb": IMDB, 43 | "fsub_id": AUTH_CHANNEL, 44 | "link": LINK_MODE, 45 | "is_verify": IS_VERIFY, 46 | "verify_time": TWO_VERIFY_GAP, 47 | "shortner_three": SHORTENER_WEBSITE3, 48 | "api_three": SHORTENER_API3, 49 | "third_verify_time": THREE_VERIFY_GAP, 50 | } 51 | 52 | def new_user(self, id, name): 53 | return dict( 54 | id=id, name=name, point=0, ban_status=dict(is_banned=False, ban_reason="") 55 | ) 56 | 57 | async def get_settings(self, group_id): 58 | chat = await self.grp.find_one({"id": int(group_id)}) 59 | if chat and "settings" in chat: 60 | return chat["settings"] 61 | else: 62 | return self.default.copy() 63 | 64 | async def find_join_req(self, id): 65 | return bool(await self.req.find_one({"id": id})) 66 | 67 | async def add_join_req(self, id): 68 | await self.req.insert_one({"id": id}) 69 | 70 | async def del_join_req(self): 71 | await self.req.drop() 72 | 73 | def new_group(self, id, title): 74 | return dict(id=id, title=title, chat_status=dict(is_disabled=False, reason="")) 75 | 76 | async def add_user(self, id, name): 77 | user = self.new_user(id, name) 78 | await self.col.insert_one(user) 79 | 80 | async def update_point(self, id): 81 | await self.col.update_one({"id": id}, {"$inc": {"point": 100}}) 82 | point = (await self.col.find_one({"id": id}))["point"] 83 | if point >= PREMIUM_POINT: 84 | seconds = REF_PREMIUM * 24 * 60 * 60 85 | oldEx = await self.users.find_one({"id": id}) 86 | if oldEx: 87 | expiry_time = oldEx["expiry_time"] + datetime.timedelta(seconds=seconds) 88 | else: 89 | expiry_time = datetime.datetime.now() + datetime.timedelta( 90 | seconds=seconds 91 | ) 92 | user_data = {"id": id, "expiry_time": expiry_time} 93 | await db.update_user(user_data) 94 | await self.col.update_one({"id": id}, {"$set": {"point": 0}}) 95 | 96 | async def get_point(self, id): 97 | newPoint = await self.col.find_one({"id": id}) 98 | return newPoint["point"] if newPoint else None 99 | 100 | async def is_user_exist(self, id): 101 | user = await self.col.find_one({"id": int(id)}) 102 | return bool(user) 103 | 104 | async def total_users_count(self): 105 | count = await self.col.count_documents({}) 106 | return count 107 | 108 | async def get_all_users(self): 109 | return self.col.find({}) 110 | 111 | async def delete_user(self, user_id): 112 | await self.col.delete_many({"id": int(user_id)}) 113 | 114 | async def delete_chat(self, id): 115 | await self.grp.delete_many({"id": int(id)}) 116 | 117 | async def get_banned(self): 118 | users = self.col.find({"ban_status.is_banned": True}) 119 | chats = self.grp.find({"chat_status.is_disabled": True}) 120 | b_chats = [chat["id"] async for chat in chats] 121 | b_users = [user["id"] async for user in users] 122 | return b_users, b_chats 123 | 124 | async def add_chat(self, chat, title): 125 | chat = self.new_group(chat, title) 126 | await self.grp.insert_one(chat) 127 | 128 | async def get_chat(self, chat): 129 | chat = await self.grp.find_one({"id": int(chat)}) 130 | return False if not chat else chat.get("chat_status") 131 | 132 | async def update_settings(self, id, settings): 133 | await self.grp.update_one({"id": int(id)}, {"$set": {"settings": settings}}) 134 | 135 | async def total_chat_count(self): 136 | count = await self.grp.count_documents({}) 137 | return count 138 | 139 | async def get_all_chats(self): 140 | return self.grp.find({}) 141 | 142 | async def get_db_size(self): 143 | return (await mydb.command("dbstats"))["dataSize"] 144 | 145 | async def get_notcopy_user(self, user_id): 146 | user_id = int(user_id) 147 | user = await self.misc.find_one({"user_id": user_id}) 148 | ist_timezone = pytz.timezone("Asia/Kolkata") 149 | if not user: 150 | res = { 151 | "user_id": user_id, 152 | "last_verified": datetime.datetime( 153 | 2020, 5, 17, 0, 0, 0, tzinfo=ist_timezone 154 | ), 155 | "second_time_verified": datetime.datetime( 156 | 2019, 5, 17, 0, 0, 0, tzinfo=ist_timezone 157 | ), 158 | } 159 | user = await self.misc.insert_one(res) 160 | return user 161 | 162 | async def update_notcopy_user(self, user_id, value: dict): 163 | user_id = int(user_id) 164 | myquery = {"user_id": user_id} 165 | newvalues = {"$set": value} 166 | return await self.misc.update_one(myquery, newvalues) 167 | 168 | async def is_user_verified(self, user_id): 169 | user = await self.get_notcopy_user(user_id) 170 | try: 171 | pastDate = user["last_verified"] 172 | except Exception: 173 | user = await self.get_notcopy_user(user_id) 174 | pastDate = user["last_verified"] 175 | ist_timezone = pytz.timezone("Asia/Kolkata") 176 | pastDate = pastDate.astimezone(ist_timezone) 177 | current_time = datetime.datetime.now(tz=ist_timezone) 178 | seconds_since_midnight = ( 179 | current_time 180 | - datetime.datetime( 181 | current_time.year, 182 | current_time.month, 183 | current_time.day, 184 | 0, 185 | 0, 186 | 0, 187 | tzinfo=ist_timezone, 188 | ) 189 | ).total_seconds() 190 | time_diff = current_time - pastDate 191 | total_seconds = time_diff.total_seconds() 192 | return total_seconds <= seconds_since_midnight 193 | 194 | async def user_verified(self, user_id): 195 | user = await self.get_notcopy_user(user_id) 196 | try: 197 | pastDate = user["second_time_verified"] 198 | except Exception: 199 | user = await self.get_notcopy_user(user_id) 200 | pastDate = user["second_time_verified"] 201 | ist_timezone = pytz.timezone("Asia/Kolkata") 202 | pastDate = pastDate.astimezone(ist_timezone) 203 | current_time = datetime.datetime.now(tz=ist_timezone) 204 | seconds_since_midnight = ( 205 | current_time 206 | - datetime.datetime( 207 | current_time.year, 208 | current_time.month, 209 | current_time.day, 210 | 0, 211 | 0, 212 | 0, 213 | tzinfo=ist_timezone, 214 | ) 215 | ).total_seconds() 216 | time_diff = current_time - pastDate 217 | total_seconds = time_diff.total_seconds() 218 | return total_seconds <= seconds_since_midnight 219 | 220 | async def use_second_shortener(self, user_id, time): 221 | user = await self.get_notcopy_user(user_id) 222 | if not user.get("second_time_verified"): 223 | ist_timezone = pytz.timezone("Asia/Kolkata") 224 | await self.update_notcopy_user( 225 | user_id, 226 | { 227 | "second_time_verified": datetime.datetime( 228 | 2019, 5, 17, 0, 0, 0, tzinfo=ist_timezone 229 | ) 230 | }, 231 | ) 232 | user = await self.get_notcopy_user(user_id) 233 | if await self.is_user_verified(user_id): 234 | try: 235 | pastDate = user["last_verified"] 236 | except Exception: 237 | user = await self.get_notcopy_user(user_id) 238 | pastDate = user["last_verified"] 239 | ist_timezone = pytz.timezone("Asia/Kolkata") 240 | pastDate = pastDate.astimezone(ist_timezone) 241 | current_time = datetime.datetime.now(tz=ist_timezone) 242 | time_difference = current_time - pastDate 243 | if time_difference > datetime.timedelta(seconds=time): 244 | pastDate = user["last_verified"].astimezone(ist_timezone) 245 | second_time = user["second_time_verified"].astimezone(ist_timezone) 246 | return second_time < pastDate 247 | return False 248 | 249 | async def use_third_shortener(self, user_id, time): 250 | user = await self.get_notcopy_user(user_id) 251 | if not user.get("third_time_verified"): 252 | ist_timezone = pytz.timezone("Asia/Kolkata") 253 | await self.update_notcopy_user( 254 | user_id, 255 | { 256 | "third_time_verified": datetime.datetime( 257 | 2018, 5, 17, 0, 0, 0, tzinfo=ist_timezone 258 | ) 259 | }, 260 | ) 261 | user = await self.get_notcopy_user(user_id) 262 | if await self.user_verified(user_id): 263 | try: 264 | pastDate = user["second_time_verified"] 265 | except Exception: 266 | user = await self.get_notcopy_user(user_id) 267 | pastDate = user["second_time_verified"] 268 | ist_timezone = pytz.timezone("Asia/Kolkata") 269 | pastDate = pastDate.astimezone(ist_timezone) 270 | current_time = datetime.datetime.now(tz=ist_timezone) 271 | time_difference = current_time - pastDate 272 | if time_difference > datetime.timedelta(seconds=time): 273 | pastDate = user["second_time_verified"].astimezone(ist_timezone) 274 | second_time = user["third_time_verified"].astimezone(ist_timezone) 275 | return second_time < pastDate 276 | return False 277 | 278 | async def create_verify_id(self, user_id: int, hash): 279 | res = {"user_id": user_id, "hash": hash, "verified": False} 280 | return await self.verify_id.insert_one(res) 281 | 282 | async def get_verify_id_info(self, user_id: int, hash): 283 | return await self.verify_id.find_one({"user_id": user_id, "hash": hash}) 284 | 285 | async def update_verify_id_info(self, user_id, hash, value: dict): 286 | myquery = {"user_id": user_id, "hash": hash} 287 | newvalues = {"$set": value} 288 | return await self.verify_id.update_one(myquery, newvalues) 289 | 290 | async def get_user(self, user_id): 291 | user_data = await self.users.find_one({"id": user_id}) 292 | return user_data 293 | 294 | async def remove_ban(self, id): 295 | ban_status = dict(is_banned=False, ban_reason="") 296 | await self.col.update_one({"id": id}, {"$set": {"ban_status": ban_status}}) 297 | 298 | async def ban_user(self, user_id, ban_reason="No Reason"): 299 | ban_status = dict(is_banned=True, ban_reason=ban_reason) 300 | await self.col.update_one({"id": user_id}, {"$set": {"ban_status": ban_status}}) 301 | 302 | async def get_ban_status(self, id): 303 | default = dict(is_banned=False, ban_reason="") 304 | user = await self.col.find_one({"id": int(id)}) 305 | if not user: 306 | return default 307 | return user.get("ban_status", default) 308 | 309 | async def update_user(self, user_data): 310 | await self.users.update_one( 311 | {"id": user_data["id"]}, {"$set": user_data}, upsert=True 312 | ) 313 | 314 | async def get_expired(self, current_time): 315 | expired_users = [] 316 | if data := self.users.find({"expiry_time": {"$lt": current_time}}): 317 | async for user in data: 318 | expired_users.append(user) 319 | return expired_users 320 | 321 | async def has_premium_access(self, user_id): 322 | user_data = await self.get_user(user_id) 323 | if user_data: 324 | expiry_time = user_data.get("expiry_time") 325 | if expiry_time is None: 326 | # User previously used the free trial, but it has ended. 327 | return False 328 | elif ( 329 | isinstance(expiry_time, datetime.datetime) 330 | and datetime.datetime.now() <= expiry_time 331 | ): 332 | return True 333 | else: 334 | await self.users.update_one( 335 | {"id": user_id}, {"$set": {"expiry_time": None}} 336 | ) 337 | return False 338 | 339 | async def check_remaining_uasge(self, user_id): 340 | user_id = user_id 341 | user_data = await self.get_user(user_id) 342 | expiry_time = user_data.get("expiry_time") 343 | # Calculate remaining time 344 | remaining_time = expiry_time - datetime.datetime.now() 345 | return remaining_time 346 | 347 | async def all_premium_users(self): 348 | count = await self.users.count_documents( 349 | {"expiry_time": {"$gt": datetime.datetime.now()}} 350 | ) 351 | return count 352 | 353 | async def update_one(self, filter_query, update_data): 354 | try: 355 | # Assuming self.client and self.users are set up properly 356 | result = await self.users.update_one(filter_query, update_data) 357 | return result.matched_count == 1 358 | except Exception as e: 359 | print(f"Error updating document: {e}") 360 | return False 361 | 362 | async def remove_premium_access(self, user_id): 363 | return await self.update_one({"id": user_id}, {"$set": {"expiry_time": None}}) 364 | 365 | async def check_trial_status(self, user_id): 366 | user_data = await self.get_user(user_id) 367 | if user_data: 368 | return user_data.get("has_free_trial", False) 369 | return False 370 | 371 | # Free Trail Remove Logic 372 | async def reset_free_trial(self, user_id=None): 373 | if user_id is None: 374 | # Reset for all users 375 | update_data = {"$set": {"has_free_trial": False}} 376 | result = await self.users.update_many( 377 | {}, update_data 378 | ) # Empty query to match all users 379 | return result.modified_count 380 | else: 381 | # Reset for a specific user 382 | update_data = {"$set": {"has_free_trial": False}} 383 | result = await self.users.update_one({"id": user_id}, update_data) 384 | return ( 385 | 1 if result.modified_count > 0 else 0 386 | ) # Return 1 if updated, 0 if not 387 | 388 | async def give_free_trial(self, user_id): 389 | # await set_free_trial_status(user_id) 390 | user_id = user_id 391 | seconds = 5 * 60 392 | expiry_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds) 393 | user_data = {"id": user_id, "expiry_time": expiry_time, "has_free_trial": True} 394 | await self.users.update_one({"id": user_id}, {"$set": user_data}, upsert=True) 395 | 396 | # JISSHU BOTS 397 | async def jisshu_set_ads_link(self, link): 398 | await self.jisshu_ads_link.update_one({}, {"$set": {"link": link}}, upsert=True) 399 | 400 | async def jisshu_get_ads_link(self): 401 | link = await self.jisshu_ads_link.find_one({}) 402 | if link is not None: 403 | return link.get("link") 404 | else: 405 | return None 406 | 407 | async def jisshu_del_ads_link(self): 408 | try: 409 | isDeleted = await self.jisshu_ads_link.delete_one({}) 410 | if isDeleted.deleted_count > 0: 411 | return True 412 | else: 413 | return False 414 | except Exception as e: 415 | print(f"Got err in db set : {e}") 416 | return False 417 | 418 | async def get_send_movie_update_status(self, bot_id): 419 | bot = await self.botcol.find_one({"id": bot_id}) 420 | if bot and bot.get("movie_update_feature"): 421 | return bot["movie_update_feature"] 422 | else: 423 | return IS_SEND_MOVIE_UPDATE 424 | 425 | async def update_send_movie_update_status(self, bot_id, enable): 426 | bot = await self.botcol.find_one({"id": int(bot_id)}) 427 | if bot: 428 | await self.botcol.update_one( 429 | {"id": int(bot_id)}, {"$set": {"movie_update_feature": enable}} 430 | ) 431 | else: 432 | await self.botcol.insert_one( 433 | {"id": int(bot_id), "movie_update_feature": enable} 434 | ) 435 | 436 | async def get_pm_search_status(self, bot_id): 437 | bot = await self.botcol.find_one({"id": bot_id}) 438 | if bot and bot.get("bot_pm_search"): 439 | return bot["bot_pm_search"] 440 | else: 441 | return IS_PM_SEARCH 442 | 443 | async def update_pm_search_status(self, bot_id, enable): 444 | bot = await self.botcol.find_one({"id": int(bot_id)}) 445 | if bot: 446 | await self.botcol.update_one( 447 | {"id": int(bot_id)}, {"$set": {"bot_pm_search": enable}} 448 | ) 449 | else: 450 | await self.botcol.insert_one({"id": int(bot_id), "bot_pm_search": enable}) 451 | 452 | async def movies_update_channel_id(self, id=None): 453 | if id is None: 454 | myLinks = await self.movies_update_channel.find_one({}) 455 | if myLinks is not None: 456 | return myLinks.get("id") 457 | else: 458 | return None 459 | return await self.movies_update_channel.update_one( 460 | {}, {"$set": {"id": id}}, upsert=True 461 | ) 462 | 463 | async def reset_group_settings(self, id): 464 | await self.grp.update_one({"id": int(id)}, {"$set": {"settings": self.default}}) 465 | 466 | 467 | db = Database() 468 | --------------------------------------------------------------------------------