File Information
70 |Name: {{file_name}}
75 |Size: {{file_size}}
76 |Disclaimer
83 |{{jisshu_disclaimer}}
84 | 87 |├── 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"» ᴜꜱᴇʀ ɪᴅ - Name: {{file_name}} Size: {{file_size}} {{jisshu_disclaimer}}{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 | {{template_ne}}
24 |
27 | File Information
70 | Disclaimer
83 | /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 | "",
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 |
3 |
/commands Enter this command inside the bot and all the commands will be set automatically.
99 |
100 |
101 |
102 |
103 |
pip3 install -U -r requirements.txt
122 | python3 bot.py
125 |
134 | 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 |
ᴄᴏɴᴛᴀᴄᴛ ᴍᴇ {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}}
{{file_size}}
51 |
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 |
Report Bugs and Contact us on Telegram Below
107 |{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 | --------------------------------------------------------------------------------