├── LICENSE
├── Procfile
├── README.md
├── Script.py
├── TechVJ
├── __init__.py
├── bot
│ ├── TechVJ
│ ├── __init__.py
│ └── clients.py
├── server
│ ├── TechVJ
│ ├── __init__.py
│ ├── exceptions.py
│ └── stream_routes.py
├── template
│ ├── TechVJ
│ ├── dl.html
│ └── req.html
└── utils
│ ├── TechVJ
│ ├── config_parser.py
│ ├── custom_dl.py
│ ├── file_properties.py
│ ├── file_size.py
│ ├── human_readable.py
│ ├── keepalive.py
│ ├── render_template.py
│ └── time_format.py
├── app.py
├── bot.py
├── clone_plugins
├── TechVJ
├── broadcast.py
├── commands.py
├── dbusers.py
├── genlink.py
└── users_api.py
├── config.py
├── logging.conf
├── plugins
├── TechVJ
├── broadcast.py
├── clone.py
├── commands.py
├── database.py
├── dbusers.py
├── genlink.py
└── users_api.py
├── requirements.txt
├── run cmd.txt
└── runtime.txt
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
2 |
3 |
5 | Tech HEro FILE STORE BOT
6 |
7 |
8 | 
9 |
/newbot
ᴛᴏ @BotFather
65 | 2) ɢɪᴠᴇ ᴀ ɴᴀᴍᴇ ꜰᴏʀ ʏᴏᴜʀ ʙᴏᴛ.
66 | 3) ɢɪᴠᴇ ᴀ ᴜɴɪǫᴜᴇ ᴜsᴇʀɴᴀᴍᴇ.
67 | 4) ᴛʜᴇɴ ʏᴏᴜ ᴡɪʟʟ ɢᴇᴛ ᴀ ᴍᴇssᴀɢᴇ ᴡɪᴛʜ ʏᴏᴜʀ ʙᴏᴛ ᴛᴏᴋᴇɴ.
68 | 5) ꜰᴏʀᴡᴀʀᴅ ᴛʜᴀᴛ ᴍᴇssᴀɢᴇ ᴛᴏ ᴍᴇ.
69 |
70 | ᴛʜᴇɴ ɪ ᴀᴍ ᴛʀʏ ᴛᴏ ᴄʀᴇᴀᴛᴇ ᴀ ᴄᴏᴘʏ ʙᴏᴛ ᴏғ ᴍᴇ ғᴏʀ ʏᴏᴜ ᴏɴʟʏ 😌"""
71 |
72 |
73 |
74 | HELP_TXT = """💢 Hᴏᴡ Tᴏ Usᴇ Tʜɪs Bᴏᴛ ☺️
75 |
76 | 🔻 /link - ʀᴇᴘʟʏ ᴛᴏ ᴀ ᴠɪᴅᴇᴏ ᴏʀ ғɪʟᴇ ᴛᴏ ɢᴇᴛ sʜᴀʀᴀʙʟᴇ ʟɪɴᴋ
77 |
78 | 🔻 /batch - sᴇɴᴅ ғɪʀsᴛ ʟɪɴᴋ ᴏғ ғɪʟᴇ sᴛᴏʀᴇ ᴄʜᴀɴɴᴇʟ ᴘᴏsᴛ ᴛʜᴇɴ ʟᴀsᴛ ᴘᴏsᴛ ʟɪɴᴋ ᴀɴᴅ ᴍᴀᴋᴇ sᴜʀᴇ ʙᴏᴛ ɪs ᴀᴅᴍɪɴ ɪɴ ʏᴏᴜʀ ғɪʟᴇ sᴛᴏʀᴇ ᴄʜᴀɴɴᴇʟ.
79 | ᴇx - /batch https://t.me/what_if_season_2_hindi_dubb/13 https://t.me/what_if_season_2_hindi_dubb/14
80 |
81 | 🔻 /base_site - ᴜsᴇ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴛᴏ sᴇᴛ ᴜʀʟ sʜᴏʀᴛɴᴇʀ ʟɪɴᴋ ᴅᴏᴍᴀɪɴ
82 | ᴇx - /base_site ʏᴏᴜʀᴅᴏᴍᴀɪɴ.ᴄᴏᴍ
83 |
84 | 🔻 /api - sᴇᴛ ʏᴏᴜʀ ᴜʀʟ sʜᴏʀᴛɴᴇʀ ᴀᴄᴄᴏᴜɴᴛ ᴀᴘɪ
85 | ᴇx - /api ʙᴀᴏᴡɢᴡᴋʟᴀᴀʙᴀᴋʟ
86 |
87 | 🔻 /deletecloned - ᴜsᴇ ᴛʜɪs ғᴏʀ ᴅᴇʟᴇᴛᴇ ʏᴏᴜʀ ᴄʟᴏɴᴇ ʙᴏᴛ
88 | ᴇx - /deletecloned ʏᴏᴜʀʙᴏᴛᴛᴏᴋᴇɴ
89 |
90 | 🔻 /broadcast - ʀᴇᴘʟʏ ᴛᴏ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴛᴏ ᴀ ᴍᴇssᴀɢᴇ ᴛᴏ ʙʀᴏᴀᴅᴄᴀsᴛ (ʙᴏᴛ ᴏᴡɴᴇʀ ᴏɴʟʏ)"""
91 |
92 |
93 |
94 |
95 | CHELP_TXT = """💢 Hᴏᴡ Tᴏ Usᴇ Tʜɪs Bᴏᴛ ☺️
96 |
97 | 🔻 /link - ʀᴇᴘʟʏ ᴛᴏ ᴀ ᴠɪᴅᴇᴏ ᴏʀ ғɪʟᴇ ᴛᴏ ɢᴇᴛ sʜᴀʀᴀʙʟᴇ ʟɪɴᴋ
98 |
99 | 🔻 /base_site - ᴜsᴇ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴛᴏ sᴇᴛ ᴜʀʟ sʜᴏʀᴛɴᴇʀ ʟɪɴᴋ ᴅᴏᴍᴀɪɴ
100 | ᴇx - /base_site ʏᴏᴜʀᴅᴏᴍᴀɪɴ.ᴄᴏᴍ
101 |
102 | 🔻 /api - sᴇᴛ ʏᴏᴜʀ ᴜʀʟ sʜᴏʀᴛɴᴇʀ ᴀᴄᴄᴏᴜɴᴛ ᴀᴘɪ
103 | ᴇx - /api ʙᴀᴏᴡɢᴡᴋʟᴀᴀʙᴀᴋʟ
104 |
105 | 🔻 /broadcast - ʀᴇᴘʟʏ ᴛᴏ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ ᴛᴏ ᴀ ᴍᴇssᴀɢᴇ ᴛᴏ ʙʀᴏᴀᴅᴄᴀsᴛ [ʙᴏᴛ ᴏᴡɴᴇʀ ᴏɴʟʏ](https://t.me/aapna_Movies) """
106 |
107 |
108 |
109 | LOG_TEXT = """#NewUser
110 |
111 | ID - {}
112 |
113 | Nᴀᴍᴇ - {}
114 | """
115 | RESTART_TXT = """
116 | Bᴏᴛ Rᴇsᴛᴀʀᴛᴇᴅ !
117 |
118 | 📅 Dᴀᴛᴇ : {}
119 | ⏰ Tɪᴍᴇ : {}
120 | 🌐 Tɪᴍᴇᴢᴏɴᴇ : Asia/Kolkata
121 | 🛠️ Bᴜɪʟᴅ Sᴛᴀᴛᴜs: v2.7.1 [ Sᴛᴀʙʟᴇ ]
"""
122 |
123 |
--------------------------------------------------------------------------------
/TechVJ/__init__.py:
--------------------------------------------------------------------------------
1 | import time
2 | StartTime = time.time()
3 | __version__ = 1.1
4 |
--------------------------------------------------------------------------------
/TechVJ/bot/TechVJ:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/TechVJ/bot/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import logging.config
3 | logging.config.fileConfig('logging.conf')
4 | logging.getLogger().setLevel(logging.INFO)
5 | logging.getLogger("pyrogram").setLevel(logging.ERROR)
6 | logging.getLogger("imdbpy").setLevel(logging.ERROR)
7 | logging.basicConfig(
8 | level=logging.INFO,
9 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
10 | )
11 | logging.getLogger("aiohttp").setLevel(logging.ERROR)
12 | logging.getLogger("aiohttp.web").setLevel(logging.ERROR)
13 |
14 | from pyrogram import Client
15 | from config import *
16 | from typing import Union, Optional, AsyncGenerator
17 | from pyrogram import types
18 | from aiohttp import web
19 |
20 | from pyrogram import Client
21 |
22 | class StreamXBot(Client):
23 |
24 | def __init__(self):
25 | super().__init__(
26 | name="vjfiletolink",
27 | api_id=API_ID,
28 | api_hash=API_HASH,
29 | bot_token=BOT_TOKEN,
30 | workers=50,
31 | plugins={"root": "plugins"},
32 | sleep_threshold=5,
33 | )
34 | async def iter_messages(
35 | self,
36 | chat_id: Union[int, str],
37 | limit: int,
38 | offset: int = 0,
39 | ) -> Optional[AsyncGenerator["types.Message", None]]:
40 | """Iterate through a chat sequentially.
41 | This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_messages` in a loop, thus saving
42 | you from the hassle of setting up boilerplate code. It is useful for getting the whole chat messages with a
43 | single call.
44 | Parameters:
45 | chat_id (``int`` | ``str``):
46 | Unique identifier (int) or username (str) of the target chat.
47 | For your personal cloud (Saved Messages) you can simply use "me" or "self".
48 | For a contact that exists in your Telegram address book you can use his phone number (str).
49 |
50 | limit (``int``):
51 | Identifier of the last message to be returned.
52 |
53 | offset (``int``, *optional*):
54 | Identifier of the first message to be returned.
55 | Defaults to 0.
56 | Returns:
57 | ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects.
58 | Example:
59 | .. code-block:: python
60 | for message in app.iter_messages("pyrogram", 1, 15000):
61 | print(message.text)
62 | """
63 | current = offset
64 | while True:
65 | new_diff = min(200, limit - current)
66 | if new_diff <= 0:
67 | return
68 | messages = await self.get_messages(chat_id, list(range(current, current+new_diff+1)))
69 | for message in messages:
70 | yield message
71 | current += 1
72 |
73 | StreamBot = StreamXBot()
74 |
75 | multi_clients = {}
76 | work_loads = {}
77 |
--------------------------------------------------------------------------------
/TechVJ/bot/clients.py:
--------------------------------------------------------------------------------
1 | # (c) adarsh-goel
2 |
3 | import asyncio
4 | import logging
5 | from config import API_HASH, API_ID, Var
6 | from pyrogram import Client
7 | from TechVJ.utils.config_parser import TokenParser
8 | from . import multi_clients, work_loads, StreamBot
9 |
10 |
11 | async def initialize_clients():
12 | multi_clients[0] = StreamBot
13 | work_loads[0] = 0
14 | all_tokens = TokenParser().parse_from_env()
15 | if not all_tokens:
16 | print("No additional clients found, using default client")
17 | return
18 |
19 | async def start_client(client_id, token):
20 | try:
21 | print(f"Starting - Client {client_id}")
22 | if client_id == len(all_tokens):
23 | await asyncio.sleep(2)
24 | print("This will take some time, please wait...")
25 | client = await Client(
26 | name=str(client_id),
27 | api_id=API_ID,
28 | api_hash=API_HASH,
29 | bot_token=token,
30 | sleep_threshold=Var.SLEEP_THRESHOLD,
31 | no_updates=True,
32 | in_memory=True
33 | ).start()
34 | work_loads[client_id] = 0
35 | return client_id, client
36 | except Exception:
37 | logging.error(f"Failed starting Client - {client_id} Error:", exc_info=True)
38 |
39 | clients = await asyncio.gather(*[start_client(i, token) for i, token in all_tokens.items()])
40 | multi_clients.update(dict(clients))
41 | if len(multi_clients) != 1:
42 | Var.MULTI_CLIENT = True
43 | print("Multi-Client Mode Enabled")
44 | else:
45 | print("No additional clients were initialized, using default client")
46 |
--------------------------------------------------------------------------------
/TechVJ/server/TechVJ:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/TechVJ/server/__init__.py:
--------------------------------------------------------------------------------
1 | from aiohttp import web
2 | from .stream_routes import routes
3 |
4 |
5 | async def web_server():
6 | web_app = web.Application(client_max_size=30000000)
7 | web_app.add_routes(routes)
8 | return web_app
9 |
--------------------------------------------------------------------------------
/TechVJ/server/exceptions.py:
--------------------------------------------------------------------------------
1 |
2 | class InvalidHash(Exception):
3 | message = "Invalid hash"
4 |
5 | class FIleNotFound(Exception):
6 | message = "File not found"
--------------------------------------------------------------------------------
/TechVJ/server/stream_routes.py:
--------------------------------------------------------------------------------
1 | import re
2 | import time
3 | import math
4 | import logging
5 | import secrets
6 | import mimetypes
7 | from aiohttp import web
8 | from aiohttp.http_exceptions import BadStatusLine
9 | from TechVJ.bot import multi_clients, work_loads, StreamBot
10 | from TechVJ.server.exceptions import FIleNotFound, InvalidHash
11 | from TechVJ import StartTime, __version__
12 | from ..utils.time_format import get_readable_time
13 | from ..utils.custom_dl import ByteStreamer
14 | from TechVJ.utils.render_template import render_page
15 | from config import Var
16 |
17 |
18 | routes = web.RouteTableDef()
19 |
20 | @routes.get("/", allow_head=True)
21 | async def root_route_handler(_):
22 | return web.json_response(
23 | {
24 | "server_status": "running",
25 | "uptime": get_readable_time(time.time() - StartTime),
26 | "telegram_bot": "@" + StreamBot.username,
27 | "connected_bots": len(multi_clients),
28 | "loads": dict(
29 | ("bot" + str(c + 1), l)
30 | for c, (_, l) in enumerate(
31 | sorted(work_loads.items(), key=lambda x: x[1], reverse=True)
32 | )
33 | ),
34 | "version": __version__,
35 | }
36 | )
37 |
38 |
39 | @routes.get(r"/watch/{path:\S+}", allow_head=True)
40 | async def stream_handler(request: web.Request):
41 | try:
42 | path = request.match_info["path"]
43 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path)
44 | if match:
45 | secure_hash = match.group(1)
46 | id = int(match.group(2))
47 | else:
48 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1))
49 | secure_hash = request.rel_url.query.get("hash")
50 | return web.Response(text=await render_page(id, secure_hash), content_type='text/html')
51 | except InvalidHash as e:
52 | raise web.HTTPForbidden(text=e.message)
53 | except FIleNotFound as e:
54 | raise web.HTTPNotFound(text=e.message)
55 | except (AttributeError, BadStatusLine, ConnectionResetError):
56 | pass
57 | except Exception as e:
58 | logging.critical(e.with_traceback(None))
59 | raise web.HTTPInternalServerError(text=str(e))
60 |
61 | @routes.get(r"/{path:\S+}", allow_head=True)
62 | async def stream_handler(request: web.Request):
63 | try:
64 | path = request.match_info["path"]
65 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path)
66 | if match:
67 | secure_hash = match.group(1)
68 | id = int(match.group(2))
69 | else:
70 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1))
71 | secure_hash = request.rel_url.query.get("hash")
72 | return await media_streamer(request, id, secure_hash)
73 | except InvalidHash as e:
74 | raise web.HTTPForbidden(text=e.message)
75 | except FIleNotFound as e:
76 | raise web.HTTPNotFound(text=e.message)
77 | except (AttributeError, BadStatusLine, ConnectionResetError):
78 | pass
79 | except Exception as e:
80 | logging.critical(e.with_traceback(None))
81 | raise web.HTTPInternalServerError(text=str(e))
82 |
83 | class_cache = {}
84 |
85 | async def media_streamer(request: web.Request, id: int, secure_hash: str):
86 | range_header = request.headers.get("Range", 0)
87 |
88 | index = min(work_loads, key=work_loads.get)
89 | faster_client = multi_clients[index]
90 |
91 | if Var.MULTI_CLIENT:
92 | logging.info(f"Client {index} is now serving {request.remote}")
93 |
94 | if faster_client in class_cache:
95 | tg_connect = class_cache[faster_client]
96 | logging.debug(f"Using cached ByteStreamer object for client {index}")
97 | else:
98 | logging.debug(f"Creating new ByteStreamer object for client {index}")
99 | tg_connect = ByteStreamer(faster_client)
100 | class_cache[faster_client] = tg_connect
101 | logging.debug("before calling get_file_properties")
102 | file_id = await tg_connect.get_file_properties(id)
103 | logging.debug("after calling get_file_properties")
104 |
105 | if file_id.unique_id[:6] != secure_hash:
106 | logging.debug(f"Invalid hash for message with ID {id}")
107 | raise InvalidHash
108 |
109 | file_size = file_id.file_size
110 |
111 | if range_header:
112 | from_bytes, until_bytes = range_header.replace("bytes=", "").split("-")
113 | from_bytes = int(from_bytes)
114 | until_bytes = int(until_bytes) if until_bytes else file_size - 1
115 | else:
116 | from_bytes = request.http_range.start or 0
117 | until_bytes = (request.http_range.stop or file_size) - 1
118 |
119 | if (until_bytes > file_size) or (from_bytes < 0) or (until_bytes < from_bytes):
120 | return web.Response(
121 | status=416,
122 | body="416: Range not satisfiable",
123 | headers={"Content-Range": f"bytes */{file_size}"},
124 | )
125 |
126 | chunk_size = 1024 * 1024
127 | until_bytes = min(until_bytes, file_size - 1)
128 |
129 | offset = from_bytes - (from_bytes % chunk_size)
130 | first_part_cut = from_bytes - offset
131 | last_part_cut = until_bytes % chunk_size + 1
132 |
133 | req_length = until_bytes - from_bytes + 1
134 | part_count = math.ceil(until_bytes / chunk_size) - math.floor(offset / chunk_size)
135 | body = tg_connect.yield_file(
136 | file_id, index, offset, first_part_cut, last_part_cut, part_count, chunk_size
137 | )
138 |
139 | mime_type = file_id.mime_type
140 | file_name = file_id.file_name
141 | disposition = "attachment"
142 |
143 | if mime_type:
144 | if not file_name:
145 | try:
146 | file_name = f"{secrets.token_hex(2)}.{mime_type.split('/')[1]}"
147 | except (IndexError, AttributeError):
148 | file_name = f"{secrets.token_hex(2)}.unknown"
149 | else:
150 | if file_name:
151 | mime_type = mimetypes.guess_type(file_id.file_name)
152 | else:
153 | mime_type = "application/octet-stream"
154 | file_name = f"{secrets.token_hex(2)}.unknown"
155 |
156 | return web.Response(
157 | status=206 if range_header else 200,
158 | body=body,
159 | headers={
160 | "Content-Type": f"{mime_type}",
161 | "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
162 | "Content-Length": str(req_length),
163 | "Content-Disposition": f'{disposition}; filename="{file_name}"',
164 | "Accept-Ranges": "bytes",
165 | },
166 | )
167 |
--------------------------------------------------------------------------------
/TechVJ/template/TechVJ:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/TechVJ/template/dl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 142 | 143 | %s 144 | 145 |
146 |143 | 144 | {{file_name}} 145 | 146 |
147 |Play with...
164 |{title}
"
89 | if CUSTOM_FILE_CAPTION:
90 | try:
91 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='')
92 | except:
93 | return
94 | await msg.edit_caption(f_caption)
95 | k = await msg.reply(f"❗️❗️❗️IMPORTANT❗️️❗️❗️\n\nThis Movie File/Video will be deleted in {AUTO_DELETE} mins 🫥 (Due to Copyright Issues).\n\nPlease forward this File/Video to your Saved Messages and Start Download there you want again [Get Here](https://t.me/aapna_Movies) ",quote=True)
96 | await asyncio.sleep(AUTO_DELETE_TIME)
97 | await msg.delete()
98 | await k.edit_text("Your File/Video is successfully deleted!!! you want again [Get Here](https://t.me/aapna_Movies) ")
99 |
100 | return
101 | except:
102 | pass
103 | return await message.reply('No such file exist.')
104 | files = files_[0]
105 | title = files.file_name
106 | size=get_size(files.file_size)
107 | f_caption=files.caption
108 | if CUSTOM_FILE_CAPTION:
109 | try:
110 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption)
111 | except Exception as e:
112 | logger.exception(e)
113 | f_caption=f_caption
114 | if f_caption is None:
115 | f_caption = f"{files.file_name}"
116 | await client.send_cached_media(
117 | chat_id=message.from_user.id,
118 | file_id=file_id,
119 | caption=f_caption,
120 | protect_content=True if pre == 'filep' else False,
121 | )
122 |
123 |
124 | @Client.on_message(filters.command('api') & filters.private)
125 | async def shortener_api_handler(client, m: Message):
126 | user_id = m.from_user.id
127 | user = await get_user(user_id)
128 | cmd = m.command
129 |
130 | if len(cmd) == 1:
131 | s = script.SHORTENER_API_MESSAGE.format(base_site=user["base_site"], shortener_api=user["shortener_api"])
132 | return await m.reply(s)
133 |
134 | elif len(cmd) == 2:
135 | api = cmd[1].strip()
136 | await update_user_info(user_id, {"shortener_api": api})
137 | await m.reply("Shortener API updated successfully to " + api)
138 | else:
139 | await m.reply("You are not authorized to use this command.")
140 |
141 | # Don't Remove Credit Tg - @Avatar_last_airbender_3_hindi
142 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@sastamarvel01?si=JmIkr6a16LRXUaIe
143 | # Ask Doubt on telegram @hero_botss
144 |
145 | @Client.on_message(filters.command("base_site") & filters.private)
146 | async def base_site_handler(client, m: Message):
147 | user_id = m.from_user.id
148 | user = await get_user(user_id)
149 | cmd = m.command
150 | text = f"/base_site (base_site)\n\nCurrent base site: None\n\n EX: /base_site shortnerdomain.com"
151 |
152 | if len(cmd) == 1:
153 | return await m.reply(text=text, disable_web_page_preview=True)
154 | elif len(cmd) == 2:
155 | base_site = cmd[1].strip()
156 | if not domain(base_site):
157 | return await m.reply(text=text, disable_web_page_preview=True)
158 | await update_user_info(user_id, {"base_site": base_site})
159 | await m.reply("Base Site updated successfully")
160 | else:
161 | await m.reply("You are not authorized to use this command.")
162 |
163 | # Don't Remove Credit Tg - @Avatar_last_airbender_3_hindi
164 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@sastamarvel01?si=JmIkr6a16LRXUaIe
165 | # Ask Doubt on telegram @hero_botss
166 |
167 |
168 | @Client.on_callback_query()
169 | async def cb_handler(client: Client, query: CallbackQuery):
170 | if query.data == "close_data":
171 | await query.message.delete()
172 | elif query.data == "start":
173 | buttons = [[
174 | InlineKeyboardButton('💝 sᴜʙsᴄʀɪʙᴇ ᴍʏ ʏᴏᴜᴛᴜʙᴇ ᴄʜᴀɴɴᴇʟ', url='https://youtube.com/@sastamarvel01?si=JmIkr6a16LRXUaIe')
175 | ],[
176 | InlineKeyboardButton('🤖 ᴄʀᴇᴀᴛᴇ ʏᴏᴜʀ ᴏᴡɴ ᴄʟᴏɴᴇ ʙᴏᴛ', url=f'https://t.me/{BOT_USERNAME}?start=clone')
177 | ],[
178 | InlineKeyboardButton('💁♀️ ʜᴇʟᴘ', callback_data='help'),
179 | InlineKeyboardButton('ᴀʙᴏᴜᴛ 🔻', callback_data='about')
180 | ]]
181 |
182 | reply_markup = InlineKeyboardMarkup(buttons)
183 | await client.edit_message_media(
184 | query.message.chat.id,
185 | query.message.id,
186 | InputMediaPhoto(random.choice(PICS))
187 | )
188 | me2 = (await client.get_me()).mention
189 | await query.message.edit_text(
190 | text=script.CLONE_START_TXT.format(query.from_user.mention, me2),
191 | reply_markup=reply_markup,
192 | parse_mode=enums.ParseMode.HTML
193 | )
194 |
195 |
196 | elif query.data == "help":
197 | buttons = [[
198 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='start'),
199 | InlineKeyboardButton('🔒 Cʟᴏsᴇ', callback_data='close_data')
200 | ]]
201 | await client.edit_message_media(
202 | query.message.chat.id,
203 | query.message.id,
204 | InputMediaPhoto(random.choice(PICS))
205 | )
206 | reply_markup = InlineKeyboardMarkup(buttons)
207 | await query.message.edit_text(
208 | text=script.CHELP_TXT,
209 | reply_markup=reply_markup,
210 | parse_mode=enums.ParseMode.HTML
211 | )
212 |
213 | elif query.data == "about":
214 | buttons = [[
215 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='start'),
216 | InlineKeyboardButton('🔒 Cʟᴏsᴇ', callback_data='close_data')
217 | ]]
218 | await client.edit_message_media(
219 | query.message.chat.id,
220 | query.message.id,
221 | InputMediaPhoto(random.choice(PICS))
222 | )
223 | me2 = (await client.get_me()).mention
224 | id = client.me.id
225 | owner = mongo_db.bots.find_one({'bot_id': id})
226 | ownerid = int(owner['user_id'])
227 | reply_markup = InlineKeyboardMarkup(buttons)
228 | await query.message.edit_text(
229 | text=script.CABOUT_TXT.format(me2, ownerid),
230 | reply_markup=reply_markup,
231 | parse_mode=enums.ParseMode.HTML
232 | )
233 |
234 |
--------------------------------------------------------------------------------
/clone_plugins/dbusers.py:
--------------------------------------------------------------------------------
1 |
2 | import motor.motor_asyncio
3 | from config import CDB_NAME, DB_URI
4 |
5 | DATABASE_NAME = CDB_NAME
6 | DATABASE_URI = DB_URI
7 |
8 |
9 | class Database:
10 |
11 | def __init__(self, uri, database_name):
12 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri)
13 | self.db = self._client[database_name]
14 | self.col = self.db.users
15 | self.grp = self.db.groups
16 |
17 |
18 | def new_user(self, id, name):
19 | return dict(
20 | id = id,
21 | name = name,
22 | ban_status=dict(
23 | is_banned=False,
24 | ban_reason="",
25 | ),
26 | )
27 |
28 | def new_group(self, id, title):
29 | return dict(
30 | id = id,
31 | title = title,
32 | chat_status=dict(
33 | is_disabled=False,
34 | reason="",
35 | ),
36 | )
37 |
38 |
39 | async def add_user(self, id, name):
40 | user = self.new_user(id, name)
41 | await self.col.insert_one(user)
42 |
43 |
44 | async def is_user_exist(self, id):
45 | user = await self.col.find_one({'id':int(id)})
46 | return bool(user)
47 |
48 |
49 | async def total_users_count(self):
50 | count = await self.col.count_documents({})
51 | return count
52 |
53 |
54 | async def get_all_users(self):
55 | return self.col.find({})
56 |
57 |
58 |
59 | async def delete_user(self, user_id):
60 | await self.col.delete_many({'id': int(user_id)})
61 |
62 |
63 | db = Database(DATABASE_URI, DATABASE_NAME)
64 |
--------------------------------------------------------------------------------
/clone_plugins/genlink.py:
--------------------------------------------------------------------------------
1 | import re
2 | from pyrogram import filters, Client, enums
3 | from plugins.database import unpack_new_file_id
4 | from clone_plugins.users_api import get_user, get_short_link
5 | import base64
6 |
7 |
8 |
9 | @Client.on_message(filters.command(['link', 'plink']))
10 | async def gen_link_s(client: Client, message):
11 | replied = message.reply_to_message
12 | if not replied:
13 | return await message.reply('Reply to a message to get a shareable link.')
14 | file_type = replied.media
15 | if file_type not in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.AUDIO, enums.MessageMediaType.DOCUMENT]:
16 | return await message.reply("Reply to a supported media")
17 | if message.has_protected_content:
18 | return await message.reply("okDa")
19 |
20 |
21 |
22 | file_id, ref = unpack_new_file_id((getattr(replied, file_type.value)).file_id)
23 | string = 'filep_' if message.text.lower().strip() == "/plink" else 'file_'
24 | string += file_id
25 | outstr = base64.urlsafe_b64encode(string.encode("ascii")).decode().strip("=")
26 | user_id = message.from_user.id
27 | user = await get_user(user_id)
28 | # Get the bot's username
29 | bot_username = (await client.get_me()).username
30 | share_link = f"https://t.me/{bot_username}?start={outstr}"
31 | await message.reply(f"⭕ ʜᴇʀᴇ ɪs ʏᴏᴜʀ ʟɪɴᴋ:\n\n🔗 ᴏʀɪɢɪɴᴀʟ ʟɪɴᴋ :- {share_link}")
32 | short_link = await get_short_link(user, share_link)
33 | await message.reply(f"⭕ ʜᴇʀᴇ ɪs ʏᴏᴜʀ ʟɪɴᴋ:\n\n🖇️ sʜᴏʀᴛ ʟɪɴᴋ :- {short_link}")
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/clone_plugins/users_api.py:
--------------------------------------------------------------------------------
1 |
2 | import requests
3 | import json
4 | from motor.motor_asyncio import AsyncIOMotorClient
5 | from config import CLONE_DB_URI, DB_NAME
6 |
7 |
8 |
9 | client = AsyncIOMotorClient(CLONE_DB_URI)
10 | db = client[DB_NAME]
11 | col = db["users"]
12 |
13 |
14 |
15 | async def get_short_link(user, link):
16 | api_key = user["shortener_api"]
17 | base_site = user["base_site"]
18 | print(user)
19 | response = requests.get(f"https://{base_site}/api?api={api_key}&url={link}")
20 | data = response.json()
21 | if data["status"] == "success" or rget.status_code == 200:
22 | return data["shortenedUrl"]
23 |
24 |
25 |
26 | async def get_user(user_id):
27 |
28 | user_id = int(user_id)
29 |
30 | user = await col.find_one({"user_id": user_id})
31 |
32 | if not user:
33 | res = {
34 | "user_id": user_id,
35 | "shortener_api": None,
36 | "base_site": None,
37 | }
38 |
39 | await col.insert_one(res)
40 | user = await col.find_one({"user_id": user_id})
41 |
42 | return user
43 |
44 |
45 |
46 | async def update_user_info(user_id, value:dict):
47 | user_id = int(user_id)
48 | myquery = {"user_id": user_id}
49 | newvalues = { "$set": value }
50 | await col.update_one(myquery, newvalues)
51 |
52 |
53 |
54 | async def total_users_count():
55 | count = await col.count_documents({})
56 | return count
57 |
58 |
59 | async def get_all_users():
60 | all_users = col.find({})
61 | return all_users
62 |
63 |
64 |
65 | async def delete_user(user_id):
66 | await col.delete_one({'user_id': int(user_id)})
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 |
2 | import re
3 | import os
4 | from os import getenv, environ
5 | from Script import script
6 | from dotenv import load_dotenv
7 |
8 | load_dotenv()
9 |
10 |
11 |
12 |
13 | id_pattern = re.compile(r'^.\d+$')
14 | def is_enabled(value, default):
15 | if value.lower() in ["true", "yes", "1", "enable", "y"]:
16 | return True
17 | elif value.lower() in ["false", "no", "0", "disable", "n"]:
18 | return False
19 | else:
20 | return default
21 |
22 |
23 |
24 | # Owner Information
25 | API_ID = int(environ.get("API_ID", "29640476"))
26 | API_HASH = environ.get("API_HASH", "824d5b93ac8c8fddcf4088a67ecd5222")
27 | ADMINS = int(environ.get("ADMINS", "6138367360"))
28 |
29 | # Database Information
30 | CLONE_DB_URI = environ.get("CLONE_DB_URI", "mongodb+srv://infotechhero890:7c2qvHdJUYqTOaMa@cluster0.veojhex.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0")
31 | CDB_NAME = environ.get("CDB_NAME", "clonevjbotz")
32 | DB_URI = environ.get("DB_URI", "mongodb+srv://thahero196:lP9Fb6aKL7T0y47U@cluster0.whs2bkj.mongodb.net/?retryWrites=true&w=majority")
33 | DB_NAME = environ.get("DB_NAME", "vjbotz")
34 |
35 |
36 | # Bot Information
37 | BOT_TOKEN = environ.get("BOT_TOKEN", "7097361555:AAHOhbFWGflLqJQcY5vWleTU-iXvfai_rXs")
38 | BOT_USERNAME = environ.get("BOT_USERNAME", "Anime_file_store1_bot") # your bot username without @
39 | PICS = (environ.get('PICS', 'https://te.legra.ph/file/66604e5911df5a0c43ffa.jpg https://graph.org/file/f5a26ac21b060d5787ea3.jpg https://graph.org/file/30539d8f1fc92423d6a19.jpg https://graph.org/file/701ff72fb43d85e073f03.jpg')).split() # Bot Start Picture
40 |
41 | # Auto Delete Information
42 | AUTO_DELETE = int(environ.get("AUTO_DELETE", "30")) # Time in Minutes
43 | AUTO_DELETE_TIME = int(environ.get("AUTO_DELETE_TIME", "1800")) # Time in Seconds
44 |
45 | # Channel Information
46 | LOG_CHANNEL = int(environ.get("LOG_CHANNEL", "-1002005121747"))
47 | FILE_STORE_CHANNEL = [int(ch) for ch in (environ.get('FILE_STORE_CHANNEL', '-1002067183105')).split()]
48 |
49 | # Don't Remove Credit Tg - @VJ_Botz
50 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@Tech_VJ
51 | # Ask Doubt on telegram @KingVJ01
52 |
53 | # File Caption Information
54 | CUSTOM_FILE_CAPTION = environ.get("CUSTOM_FILE_CAPTION", f"{script.CAPTION}")
55 | BATCH_FILE_CAPTION = environ.get("BATCH_FILE_CAPTION", CUSTOM_FILE_CAPTION)
56 |
57 | # Enable - True or Disable - False
58 | PROTECT_CONTENT = is_enabled((environ.get('PROTECT_CONTENT', "False")), False)
59 | PUBLIC_FILE_STORE = is_enabled((environ.get('PUBLIC_FILE_STORE', "True")), True)
60 |
61 |
62 |
63 | # File Stream Config
64 | class Var(object):
65 | MULTI_CLIENT = True
66 | name = str(getenv('name', 'filetolinkvjbot'))
67 | SLEEP_THRESHOLD = int(getenv('SLEEP_THRESHOLD', '60'))
68 | WORKERS = int(getenv('WORKERS', '4'))
69 | BIN_CHANNEL = int(getenv('BIN_CHANNEL', '-1002124914386'))
70 | PORT = int(getenv('PORT', 8080))
71 | BIND_ADRESS = str(getenv('WEB_SERVER_BIND_ADDRESS', '0.0.0.0'))
72 | PING_INTERVAL = int(environ.get("PING_INTERVAL", "1200")) # 20 minutes
73 | NO_PORT = bool(getenv('NO_PORT', False))
74 | APP_NAME = None
75 | if 'DYNO' in environ:
76 | ON_HEROKU = True
77 | APP_NAME = str(getenv('APP_NAME'))
78 |
79 | else:
80 | ON_HEROKU = False
81 | FQDN = str(getenv('FQDN', BIND_ADRESS)) if not ON_HEROKU or getenv('FQDN') else APP_NAME+'.herokuapp.com'
82 | HAS_SSL=bool(getenv('HAS_SSL',False))
83 | if HAS_SSL:
84 | URL = "https://file-store-bot-ajay-client.onrender.com"
85 | else:
86 | URL = "https://file-store-bot-ajay-client.onrender.com"
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/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/TechVJ:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugins/broadcast.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | from pyrogram.errors import InputUserDeactivated, UserNotParticipant, FloodWait, UserIsBlocked, PeerIdInvalid
4 | from plugins.dbusers import db
5 | from pyrogram import Client, filters
6 | from config import ADMINS
7 | import asyncio
8 | import datetime
9 | import time
10 | import logging
11 |
12 |
13 |
14 | logger = logging.getLogger(__name__)
15 | logger.setLevel(logging.INFO)
16 |
17 |
18 |
19 | async def broadcast_messages(user_id, message):
20 | try:
21 | await message.copy(chat_id=user_id)
22 | return True, "Success"
23 | except FloodWait as e:
24 | await asyncio.sleep(e.x)
25 | return await broadcast_messages(user_id, message)
26 | except InputUserDeactivated:
27 | await db.delete_user(int(user_id))
28 | logging.info(f"{user_id}-Removed from Database, since deleted account.")
29 | return False, "Deleted"
30 | except UserIsBlocked:
31 | logging.info(f"{user_id} -Blocked the bot.")
32 | return False, "Blocked"
33 | except PeerIdInvalid:
34 | await db.delete_user(int(user_id))
35 | logging.info(f"{user_id} - PeerIdInvalid")
36 | return False, "Error"
37 | except Exception as e:
38 | return False, "Error"
39 |
40 |
41 |
42 |
43 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply)
44 | async def verupikkals(bot, message):
45 | users = await db.get_all_users()
46 | b_msg = message.reply_to_message
47 | sts = await message.reply_text(
48 | text='Broadcasting your messages...'
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 |
57 |
58 |
59 | success = 0
60 | async for user in users:
61 | if 'id' in user:
62 | pti, sh = await broadcast_messages(int(user['id']), b_msg)
63 | if pti:
64 | success += 1
65 | elif pti == False:
66 | if sh == "Blocked":
67 | blocked += 1
68 | elif sh == "Deleted":
69 | deleted += 1
70 | elif sh == "Error":
71 | failed += 1
72 | done += 1
73 | if not done % 20:
74 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}")
75 | else:
76 | # Handle the case where 'id' key is missing in the user dictionary
77 | done += 1
78 | failed += 1
79 | if not done % 20:
80 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}")
81 |
82 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time))
83 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}")
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/plugins/clone.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import re
4 | import logging
5 | from pymongo import MongoClient
6 | from Script import script
7 | from pyrogram import Client, filters
8 | from pyrogram.types import Message
9 | from pyrogram.errors.exceptions.bad_request_400 import AccessTokenExpired, AccessTokenInvalid
10 | from config import API_ID, API_HASH, ADMINS, DB_NAME
11 | from config import DB_URI as MONGO_URL
12 |
13 | mongo_client = MongoClient(MONGO_URL)
14 | mongo_db = mongo_client["cloned_vjbotz"]
15 | mongo_collection = mongo_db[DB_NAME]
16 |
17 | @Client.on_message(filters.command("clone") & filters.private)
18 | async def clone(client, message):
19 | await message.reply_text(script.CLONE_TXT)
20 |
21 |
22 |
23 | @Client.on_message((filters.regex(r'\d[0-9]{8,10}:[0-9A-Za-z_-]{35}')) & filters.private)
24 | async def on_clone(client, message):
25 | try:
26 | user_id = message.from_user.id
27 | user_name = message.from_user.first_name
28 | bot_token = re.findall(r'\d[0-9]{8,10}:[0-9A-Za-z_-]{35}', message.text, re.IGNORECASE)
29 | bot_token = bot_token[0] if bot_token else None
30 | bot_id = re.findall(r'\d[0-9]{8,10}', message.text)
31 | bots = list(mongo_db.bots.find())
32 | bot_tokens = None # Initialize bot_tokens variable
33 |
34 | for bot in bots:
35 | bot_tokens = bot['token']
36 |
37 | forward_from_id = message.forward_from.id if message.forward_from else None
38 | if bot_tokens == bot_token and forward_from_id == 93372553:
39 | await message.reply_text("**©️ ᴛʜɪs ʙᴏᴛ ɪs ᴀʟʀᴇᴀᴅʏ ᴄʟᴏɴᴇᴅ ʙᴀʙʏ 🐥**")
40 | return
41 |
42 | if not forward_from_id != 93372553:
43 | msg = await message.reply_text("**👨💻 ᴡᴀɪᴛ ᴀ ᴍɪɴᴜᴛᴇ ɪ ᴀᴍ ᴄʀᴇᴀᴛɪɴɢ ʏᴏᴜʀ ʙᴏᴛ ❣️@hero_botss**")
44 | try:
45 | ai = Client(
46 | f"{bot_token}", API_ID, API_HASH,
47 | bot_token=bot_token,
48 | plugins={"root": "clone_plugins"},
49 | )
50 |
51 | await ai.start()
52 | bot = await ai.get_me()
53 | details = {
54 | 'bot_id': bot.id,
55 | 'is_bot': True,
56 | 'user_id': user_id,
57 | 'name': bot.first_name,
58 | 'token': bot_token,
59 | 'username': bot.username
60 | }
61 | mongo_db.bots.insert_one(details)
62 | await msg.edit_text(f"sᴜᴄᴄᴇssғᴜʟʟʏ ᴄʟᴏɴᴇᴅ ʏᴏᴜʀ ʙᴏᴛ: @{bot.username}.\n\nʏᴏᴜ ᴄᴀɴ ᴀʟsᴏ sᴇᴛ ʏᴏᴜʀ sʜᴏʀᴛɴᴇʀ ɪɴ ʏᴏᴜʀ ᴄʟᴏɴᴇᴅ ʙᴏᴛ ғᴏʀ ᴍᴏʀᴇ ɪɴғᴏ sᴛᴀʀᴛ ʏᴏᴜʀ ᴄʟᴏɴᴇᴅ ʙᴏᴛ @hero_botss")
63 | except BaseException as e:
64 | logging.exception("Error while cloning bot.")
65 | await msg.edit_text(f"⚠️ Bot Error:\n\n{e}
\n\n**Kindly forward this message to @hero_botss to get assistance.**")
66 | except Exception as e:
67 | logging.exception("Error while handling message.")
68 |
69 | @Client.on_message(filters.command("deletecloned") & filters.private)
70 | async def delete_cloned_bot(client, message):
71 | try:
72 | bot_token = re.findall(r'\d[0-9]{8,10}:[0-9A-Za-z_-]{35}', message.text, re.IGNORECASE)
73 | bot_token = bot_token[0] if bot_token else None
74 | bot_id = re.findall(r'\d[0-9]{8,10}', message.text)
75 |
76 | mongo_collection = mongo_db.bots
77 |
78 | cloned_bot = mongo_collection.find_one({"token": bot_token})
79 | if cloned_bot:
80 | mongo_collection.delete_one({"token": bot_token})
81 | await message.reply_text("**🤖 ᴛʜᴇ ᴄʟᴏɴᴇᴅ ʙᴏᴛ ʜᴀs ʙᴇᴇɴ ʀᴇᴍᴏᴠᴇᴅ ғʀᴏᴍ ᴛʜᴇ ʟɪsᴛ ᴀɴᴅ ɪᴛs ᴅᴇᴛᴀɪʟs ʜᴀᴠᴇ ʙᴇᴇɴ ʀᴇᴍᴏᴠᴇᴅ ғʀᴏᴍ ᴛʜᴇ ᴅᴀᴛᴀʙᴀsᴇ.@hero_botss ☠️**")
82 | else:
83 | await message.reply_text("**⚠️ ᴛʜᴇ ʙᴏᴛ ᴛᴏᴋᴇɴ ᴘʀᴏᴠɪᴅᴇᴅ ɪs ɴᴏᴛ ɪɴ ᴛʜᴇ ᴄʟᴏɴᴇᴅ ʟɪsᴛ.@hero_botss**")
84 | except Exception as e:
85 | logging.exception("Error while deleting cloned bot.")
86 | await message.reply_text("An error occurred while deleting the cloned bot.@hero_botss")
87 |
88 | # Don't Remove Credit Tg - @VJ_Botz
89 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@Tech_VJ
90 | # Ask Doubt on telegram @KingVJ01
91 |
92 | async def restart_bots():
93 | logging.info("Restarting all bots........@hero_botss")
94 | bots = list(mongo_db.bots.find())
95 | for bot in bots:
96 | bot_token = bot['token']
97 | try:
98 | ai = Client(
99 | f"{bot_token}", API_ID, API_HASH,
100 | bot_token=bot_token,
101 | plugins={"root": "clone_plugins"},
102 | )
103 | await ai.start()
104 | except Exception as e:
105 | logging.exception(f"Error while restarting bot with token {bot_token}: {e}")
106 |
107 |
--------------------------------------------------------------------------------
/plugins/commands.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging
3 | import random
4 | import asyncio
5 | from validators import domain
6 | from Script import script
7 | from plugins.dbusers import db
8 | from pyrogram import Client, filters, enums
9 | from plugins.users_api import get_user, update_user_info
10 | from plugins.database import get_file_details
11 | from pyrogram.errors import ChatAdminRequired, FloodWait
12 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message, CallbackQuery, InputMediaPhoto
13 | from config import Var, LOG_CHANNEL, PICS, BATCH_FILE_CAPTION, CUSTOM_FILE_CAPTION, AUTO_DELETE_TIME, AUTO_DELETE, ADMINS
14 | import re
15 | import json
16 | import base64
17 | from urllib.parse import quote_plus
18 | from TechVJ.utils.file_properties import get_name, get_hash, get_media_file_size
19 | logger = logging.getLogger(__name__)
20 |
21 | BATCH_FILES = {}
22 |
23 | # Don't Remove Credit Tg - @VJ_Botz
24 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@Tech_VJ
25 | # Ask Doubt on telegram @KingVJ01
26 |
27 |
28 | def get_size(size):
29 | """Get size in readable format"""
30 |
31 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"]
32 | size = float(size)
33 | i = 0
34 | while size >= 1024.0 and i < len(units):
35 | i += 1
36 | size /= 1024.0
37 | return "%.2f %s" % (size, units[i])
38 |
39 |
40 | async def delete_after_delay(message: Message, delay):
41 | await asyncio.sleep(AUTO_DELETE_TIME)
42 | await message.delete()
43 |
44 | # Don't Remove Credit Tg - @VJ_Botz
45 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@Tech_VJ
46 | # Ask Doubt on telegram @KingVJ0
47 |
48 |
49 | @Client.on_message(filters.command("start") & filters.incoming)
50 | async def start(client, message):
51 | if not await db.is_user_exist(message.from_user.id):
52 | await db.add_user(message.from_user.id, message.from_user.first_name)
53 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT.format(message.from_user.id, message.from_user.mention))
54 | if len(message.command) != 2:
55 | buttons = [[
56 | InlineKeyboardButton( '💝 sᴜʙsᴄʀɪʙᴇ ᴍʏ ʏᴏᴜᴛᴜʙᴇ ᴄʜᴀɴɴᴇʟ', url='https://youtube.com/@sastamarvel01?si=KiYYZ5mByFO-O_fl')
57 | ],[
58 | InlineKeyboardButton( '💝 movies ', url='https://t.me/+ccx-5xVHyro3ZjNl')
59 | ],[
60 | InlineKeyboardButton('🔍 sᴜᴘᴘᴏʀᴛ ɢʀᴏᴜᴘ', url='https://t.me/+ccx-5xVHyro3ZjNl'),
61 | InlineKeyboardButton('🤖 ᴜᴘᴅᴀᴛᴇ ᴄʜᴀɴɴᴇʟ', url='https://t.me/aapna_Movies')
62 | ],[
63 | InlineKeyboardButton('🤖 ᴄʀᴇᴀᴛᴇ ʏᴏᴜʀ ᴏᴡɴ ᴄʟᴏɴᴇ ʙᴏᴛ', callback_data='clone')
64 | ],[
65 | InlineKeyboardButton('💁♀️ ʜᴇʟᴘ', callback_data='help'),
66 | InlineKeyboardButton('😊 ᴀʙᴏᴜᴛ', callback_data='about')
67 | ]]
68 | reply_markup = InlineKeyboardMarkup(buttons)
69 | me2 = (await client.get_me()).mention
70 | m=await message.reply_sticker("CAACAgUAAxkBAAIhuGTHNIDjN6W-9OgK2xPXQSiDYpm-AAIFAgACD_PRVn7ikCL5fe76HgQ")
71 | await asyncio.sleep(1)
72 | await m.delete()
73 | await message.reply_photo(
74 | photo=random.choice(PICS),
75 | caption=script.START_TXT.format(message.from_user.mention, me2),
76 | reply_markup=reply_markup
77 | )
78 | return
79 |
80 |
81 | data = message.command[1]
82 | try:
83 | pre, file_id = data.split('_', 1)
84 | except:
85 | file_id = data
86 | pre = ""
87 | if data.split("-", 1)[0] == "BATCH":
88 | sts = await message.reply("**🔺 ᴘʟᴇᴀsᴇ ᴡᴀɪᴛ**")
89 | file_id = data.split("-", 1)[1]
90 | msgs = BATCH_FILES.get(file_id)
91 | if not msgs:
92 | file = await client.download_media(file_id)
93 | try:
94 | with open(file) as file_data:
95 | msgs=json.loads(file_data.read())
96 | except:
97 | await sts.edit("FAILED")
98 | return await client.send_message(LOG_CHANNEL, "UNABLE TO OPEN FILE.")
99 | os.remove(file)
100 | BATCH_FILES[file_id] = msgs
101 |
102 | for msg in msgs:
103 | title = msg.get("title")
104 | size=get_size(int(msg.get("size", 0)))
105 | f_caption=msg.get("caption", "")
106 | if BATCH_FILE_CAPTION:
107 | try:
108 | f_caption=BATCH_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption)
109 | except Exception as e:
110 | logger.exception(e)
111 | f_caption=f_caption
112 | if f_caption is None:
113 | f_caption = f"{title}"
114 | try:
115 | h = await message.reply_text(f"❗️❗️❗️IMPORTANT❗️️❗️❗️\n\nThis Movie File/Video will be deleted in {AUTO_DELETE} minutes 🫥 (Due to Copyright Issues).\n\nPlease forward this File/Video to your Saved Messages and Start Download there ")
116 | quote=True,
117 |
118 | k = await client.send_cached_media(
119 | chat_id=message.from_user.id,
120 | file_id=msg.get("file_id"),
121 | caption=f_caption,
122 | protect_content=msg.get('protect', False),
123 | )
124 |
125 | asyncio.create_task(delete_after_delay(k, AUTO_DELETE_TIME))
126 | asyncio.create_task(delete_after_delay(h, AUTO_DELETE_TIME))
127 | except FloodWait as e:
128 | await asyncio.sleep(e.x)
129 | logger.warning(f"Floodwait of {e.x} sec.")
130 | await client.send_cached_media(
131 | chat_id=message.from_user.id,
132 | file_id=msg.get("file_id"),
133 | caption=f_caption,
134 | protect_content=msg.get('protect', False),
135 | )
136 | except Exception as e:
137 | logger.warning(e, exc_info=True)
138 | continue
139 | await asyncio.sleep(1)
140 | await sts.delete()
141 | return
142 |
143 |
144 | elif data.split("-", 1)[0] == "DSTORE":
145 | sts = await message.reply("**🔺 ᴘʟᴇᴀsᴇ ᴡᴀɪᴛ**")
146 | b_string = data.split("-", 1)[1]
147 | decoded = (base64.urlsafe_b64decode(b_string + "=" * (-len(b_string) % 4))).decode("ascii")
148 | await message.reply_text(f"❗️❗️❗️IMPORTANT❗️️❗️❗️\n\nThis Movie File/Video will be deleted in {AUTO_DELETE} mins 🫥 (Due to Copyright Issues).\n\nPlease forward this File/Video to your Saved Messages and Start Download there you want again @group_discd")
149 |
150 | try:
151 | f_msg_id, l_msg_id, f_chat_id, protect = decoded.split("_", 3)
152 | except:
153 | f_msg_id, l_msg_id, f_chat_id = decoded.split("_", 2)
154 | protect = "/pbatch" if PROTECT_CONTENT else "batch"
155 | diff = int(l_msg_id) - int(f_msg_id)
156 | async for msg in client.iter_messages(int(f_chat_id), int(l_msg_id), int(f_msg_id)):
157 | if msg.media:
158 | media = getattr(msg, msg.media.value)
159 | if BATCH_FILE_CAPTION:
160 | try:
161 | f_caption=BATCH_FILE_CAPTION.format(file_name=getattr(media, 'file_name', ''), file_size=getattr(media, 'file_size', ''), file_caption=getattr(msg, 'caption', ''))
162 | except Exception as e:
163 | logger.exception(e)
164 | f_caption = getattr(msg, 'caption', '')
165 | else:
166 | media = getattr(msg, msg.media)
167 | file_name = getattr(media, 'file_name', '')
168 | f_caption = getattr(msg, 'caption', file_name)
169 | try:
170 | h = await message.reply_text(f"❗️❗️❗️IMPORTANT❗️️❗️❗️\n\nThis Movie File/Video will be deleted in {AUTO_DELETE} minutes 🫥 (Due to Copyright Issues).\n\nPlease forward this File/Video to your Saved Messages and Start Download there If you want File again @group_discd")
171 | k = await msg.copy(message.chat.id, caption=f_caption, protect_content=True if protect == "/pbatch" else False)
172 |
173 | asyncio.create_task(delete_after_delay(k, AUTO_DELETE_TIME))
174 | asyncio.create_task(delete_after_delay(h, AUTO_DELETE_TIME))
175 | except FloodWait as e:
176 | await asyncio.sleep(e.x)
177 | await msg.copy(message.chat.id, caption=f_caption, protect_content=True if protect == "/pbatch" else False)
178 | except Exception as e:
179 | logger.exception(e)
180 | continue
181 | elif msg.empty:
182 | continue
183 | else:
184 | try:
185 | await msg.copy(message.chat.id, protect_content=True if protect == "/pbatch" else False)
186 | except FloodWait as e:
187 | await asyncio.sleep(e.x)
188 | await msg.copy(message.chat.id, protect_content=True if protect == "/pbatch" else False)
189 | except Exception as e:
190 | logger.exception(e)
191 | continue
192 | await asyncio.sleep(1)
193 | return await sts.delete()
194 |
195 |
196 |
197 | files_ = await get_file_details(file_id)
198 | if not files_:
199 | pre, file_id = ((base64.urlsafe_b64decode(data + "=" * (-len(data) % 4))).decode("ascii")).split("_", 1)
200 | try:
201 | msg = await client.send_cached_media(
202 | chat_id=message.from_user.id,
203 | file_id=file_id,
204 | protect_content=True if pre == 'filep' else False,
205 | )
206 | filetype = msg.media
207 | file = getattr(msg, filetype.value)
208 | title = '' + ' '.join(filter(lambda x: not x.startswith('[') and not x.startswith('@'), file.file_name.split()))
209 | size=get_size(file.file_size)
210 | f_caption = f"{title}
"
211 | if CUSTOM_FILE_CAPTION:
212 | try:
213 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='')
214 | except:
215 | return
216 |
217 | await msg.edit_caption(f_caption)
218 | g = await msg.reply_text(
219 | text=f"**••If Any Problem To Open File Please Message In Here👇👇**",
220 | quote=True,
221 | disable_web_page_preview=True,
222 | reply_markup=InlineKeyboardMarkup(
223 | [
224 | [
225 | InlineKeyboardButton('🚀 New Anime Update🖥️', url="https://t.me/group_discd")]
226 | ]
227 | )
228 | )
229 | k = await msg.reply(f"❗️❗️❗️IMPORTANT❗️️❗️❗️\n\nThis Movie File/Video will be deleted in {AUTO_DELETE} mins 🫥 (Due to Copyright Issues).\n\nPlease forward this File/Video to your Saved Messages and Start Download there You Want Again @group_discd ",quote=True)
230 | await asyncio.sleep(AUTO_DELETE_TIME)
231 | await msg.delete()
232 | await g.delete()
233 | await k.edit_text("Your File/Video is successfully deleted!!! You Want Again [Get Here](https://t.me/aapna_Movies).")
234 | await m.edit_text("❤️🔥.")
235 | await asyncio.sleep(1)
236 | await m.delete()
237 | return
238 | except:
239 | pass
240 | return await message.reply('No such file exist.')
241 |
242 |
243 |
244 | files = files_[0]
245 | title = files.file_name
246 | size=get_size(files.file_size)
247 | f_caption=files.caption
248 | if CUSTOM_FILE_CAPTION:
249 | try:
250 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption)
251 | except Exception as e:
252 | logger.exception(e)
253 | f_caption=f_caption
254 | if f_caption is None:
255 | f_caption = f"{files.file_name}"
256 | await client.send_cached_media(
257 | chat_id=message.from_user.id,
258 | file_id=file_id,
259 | caption=f_caption,
260 | protect_content=True if pre == 'filep' else False,
261 | )
262 |
263 | # Don't Remove Credit Tg - @VJ_Botz
264 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@Tech_VJ
265 | # Ask Doubt on telegram @KingVJ01
266 |
267 | @Client.on_message(filters.command('api') & filters.private)
268 | async def shortener_api_handler(client, m: Message):
269 | user_id = m.from_user.id
270 | user = await get_user(user_id)
271 | cmd = m.command
272 |
273 | if len(cmd) == 1:
274 | s = script.SHORTENER_API_MESSAGE.format(base_site=user["base_site"], shortener_api=user["shortener_api"])
275 | return await m.reply(s)
276 |
277 | elif len(cmd) == 2:
278 | api = cmd[1].strip()
279 | await update_user_info(user_id, {"shortener_api": api})
280 | await m.reply("Shortener API updated successfully to " + api)
281 |
282 |
283 |
284 | @Client.on_message(filters.command("base_site") & filters.private)
285 | async def base_site_handler(client, m: Message):
286 | user_id = m.from_user.id
287 | user = await get_user(user_id)
288 | cmd = m.command
289 | text = f"`/base_site (base_site)`\n\nCurrent base site: None\n\n EX: `/base_site shortnerdomain.com`"
290 | if len(cmd) == 1:
291 | return await m.reply(text=text, disable_web_page_preview=True)
292 | elif len(cmd) == 2:
293 | base_site = cmd[1].strip()
294 | if not domain(base_site):
295 | return await m.reply(text=text, disable_web_page_preview=True)
296 | await update_user_info(user_id, {"base_site": base_site})
297 | await m.reply("Base Site updated successfully")
298 |
299 |
300 |
301 | @Client.on_callback_query()
302 | async def cb_handler(client: Client, query: CallbackQuery):
303 | if query.data == "close_data":
304 | await query.message.delete()
305 | elif query.data == "about":
306 | buttons = [[
307 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='start'),
308 | InlineKeyboardButton('🔒 Cʟᴏsᴇ', callback_data='close_data')
309 | ]]
310 | await client.edit_message_media(
311 | query.message.chat.id,
312 | query.message.id,
313 | InputMediaPhoto(random.choice(PICS))
314 | )
315 | reply_markup = InlineKeyboardMarkup(buttons)
316 | me2 = (await client.get_me()).mention
317 | await query.message.edit_text(
318 | text=script.ABOUT_TXT.format(me2),
319 | reply_markup=reply_markup,
320 | parse_mode=enums.ParseMode.HTML
321 | )
322 |
323 |
324 |
325 | elif query.data == "start":
326 | buttons = [[
327 | InlineKeyboardButton( '💝 sᴜʙsᴄʀɪʙᴇ ᴍʏ ʏᴏᴜᴛᴜʙᴇ ᴄʜᴀɴɴᴇʟ', url='https://youtube.com/@sastamarvel01?si=KiYYZ5mByFO-O_fl')
328 | ],[
329 | InlineKeyboardButton( '💝 movies ', url='https://t.me/+ccx-5xVHyro3ZjNl')
330 | ],[
331 | InlineKeyboardButton('🔍 sᴜᴘᴘᴏʀᴛ ɢʀᴏᴜᴘ', url='https://t.me/+ccx-5xVHyro3ZjNl'),
332 | InlineKeyboardButton('🤖 ᴜᴘᴅᴀᴛᴇ ᴄʜᴀɴɴᴇʟ', url='https://t.me/aapna_Movies')
333 | ],[
334 | InlineKeyboardButton('🤖 ᴄʀᴇᴀᴛᴇ ʏᴏᴜʀ ᴏᴡɴ ᴄʟᴏɴᴇ ʙᴏᴛ', callback_data='clone')
335 | ],[
336 | InlineKeyboardButton('💁♀️ ʜᴇʟᴘ', callback_data='help'),
337 | InlineKeyboardButton('😊 ᴀʙᴏᴜᴛ', callback_data='about')
338 | ]]
339 |
340 | reply_markup = InlineKeyboardMarkup(buttons)
341 | await client.edit_message_media(
342 | query.message.chat.id,
343 | query.message.id,
344 | InputMediaPhoto(random.choice(PICS))
345 | )
346 | me2 = (await client.get_me()).mention
347 | m=await message.reply_sticker("CAACAgUAAxkBAAIhuGTHNIDjN6W-9OgK2xPXQSiDYpm-AAIFAgACD_PRVn7ikCL5fe76HgQ")
348 | await asyncio.sleep(1)
349 | await m.delete()
350 | await query.message.edit_text(
351 | text=script.START_TXT.format(query.from_user.mention, me2),
352 | reply_markup=reply_markup,
353 | parse_mode=enums.ParseMode.HTML
354 | )
355 |
356 | # Don't Remove Credit Tg - @VJ_Botz
357 | # Subscribe YouTube Channel For Amazing Bot https://youtube.com/@Tech_VJ
358 | # Ask Doubt on telegram @KingVJ01
359 |
360 | elif query.data == "clone":
361 | buttons = [[
362 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='start'),
363 | InlineKeyboardButton('🔒 Cʟᴏsᴇ', callback_data='close_data')
364 | ]]
365 | await client.edit_message_media(
366 | query.message.chat.id,
367 | query.message.id,
368 | InputMediaPhoto(random.choice(PICS))
369 | )
370 | reply_markup = InlineKeyboardMarkup(buttons)
371 | await query.message.edit_text(
372 | text=script.CLONE_TXT.format(query.from_user.mention),
373 | reply_markup=reply_markup,
374 | parse_mode=enums.ParseMode.HTML
375 | )
376 |
377 |
378 |
379 | elif query.data == "help":
380 | buttons = [[
381 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='start'),
382 | InlineKeyboardButton('🔒 Cʟᴏsᴇ', callback_data='close_data')
383 | ]]
384 | await client.edit_message_media(
385 | query.message.chat.id,
386 | query.message.id,
387 | InputMediaPhoto(random.choice(PICS))
388 | )
389 | reply_markup = InlineKeyboardMarkup(buttons)
390 | await query.message.edit_text(
391 | text=script.HELP_TXT,
392 | reply_markup=reply_markup,
393 | parse_mode=enums.ParseMode.HTML
394 | )
395 |
396 |
397 |
398 | elif query.data.startswith("generate_stream_link"):
399 | _, file_id = query.data.split(":")
400 | try:
401 | user_id = query.from_user.id
402 | username = query.from_user.mention
403 |
404 | log_msg = await client.send_cached_media(
405 | chat_id=LOG_CHANNEL,
406 | file_id=file_id,
407 | )
408 | fileName = {quote_plus(get_name(log_msg))}
409 | stream = f"{Var.URL}watch/{str(log_msg.id)}/{quote_plus(get_name(log_msg))}?hash={get_hash(log_msg)}"
410 | download = f"{Var.URL}{str(log_msg.id)}/{quote_plus(get_name(log_msg))}?hash={get_hash(log_msg)}"
411 |
412 | m = await message.reply_sticker("CAACAgUAAxkBAAIhuGTHNIDjN6W-9OgK2xPXQSiDYpm-AAIFAgACD_PRVn7ikCL5fe76HgQ")
413 | await asyncio.sleep(1)
414 | await m.delete()
415 |
416 | xo = await query.message.reply_text(f'👾')
417 | await asyncio.sleep(1)
418 | await xo.delete()
419 |
420 | await log_msg.reply_text(
421 | text=f"•• ʟɪɴᴋ ɢᴇɴᴇʀᴀᴛᴇᴅ ꜰᴏʀ ɪᴅ #{user_id} \n•• ᴜꜱᴇʀɴᴀᴍᴇ : {username} \n\n•• ᖴᎥᒪᗴ Nᗩᗰᗴ : {fileName}",
422 | quote=True,
423 | disable_web_page_preview=True,
424 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🚀 Fast Download 🚀", url= download), # we download Link
425 | InlineKeyboardButton('🖥️ Watch online 🖥️', url= stream)]]) # web stream Link
426 | )
427 | await query.message.reply_text(
428 | text="•• ʟɪɴᴋ ɢᴇɴᴇʀᴀᴛᴇᴅ ☠︎⚔",
429 | quote=True,
430 | disable_web_page_preview=True,
431 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🚀 Fast Download 🚀", url= download)], # we download Link
432 | [
433 | InlineKeyboardButton('🖥️ Watch online 🖥️', url= stream)], # web stream Link
434 | [
435 | InlineKeyboardButton('📁 Want File again ', url='https://t.me/aapna_Movies')],
436 | [
437 | InlineKeyboardButton('🔍 sᴜᴘᴘᴏʀᴛ ɢʀᴏᴜᴘ', url='https://t.me/+ccx-5xVHyro3ZjNl')]
438 | ]
439 | )
440 | )
441 | except Exception as e:
442 | print(e) # print the error message
443 | await query.answer(f"☣something went wrong\n\n{e}", show_alert=True)
444 | return
445 |
446 |
447 |
--------------------------------------------------------------------------------
/plugins/database.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import logging
4 | from struct import pack
5 | import re
6 | import base64
7 | from pyrogram.file_id import FileId
8 | from pymongo.errors import DuplicateKeyError
9 | from umongo import Instance, Document, fields
10 | from motor.motor_asyncio import AsyncIOMotorClient
11 | from config import DB_URI, DB_NAME
12 |
13 |
14 | logger = logging.getLogger(__name__)
15 | logger.setLevel(logging.INFO)
16 |
17 |
18 |
19 | COLLECTION_NAME = "Telegram_Files"
20 |
21 |
22 |
23 |
24 | client = AsyncIOMotorClient(DB_URI)
25 | db = client[DB_NAME]
26 | instance = Instance.from_db(db)
27 |
28 |
29 |
30 | @instance.register
31 | class Media(Document):
32 | file_id = fields.StrField(attribute='_id')
33 | file_ref = fields.StrField(allow_none=True)
34 | file_name = fields.StrField(required=True)
35 | file_size = fields.IntField(required=True)
36 | file_type = fields.StrField(allow_none=True)
37 | mime_type = fields.StrField(allow_none=True)
38 | caption = fields.StrField(allow_none=True)
39 |
40 | class Meta:
41 | indexes = ('$file_name', )
42 | collection_name = COLLECTION_NAME
43 |
44 |
45 |
46 |
47 | async def get_file_details(query):
48 | filter = {'file_id': query}
49 | cursor = Media.find(filter)
50 | filedetails = await cursor.to_list(length=1)
51 | return filedetails
52 |
53 |
54 |
55 | def encode_file_id(s: bytes) -> str:
56 | r = b""
57 | n = 0
58 |
59 | for i in s + bytes([22]) + bytes([4]):
60 | if i == 0:
61 | n += 1
62 | else:
63 | if n:
64 | r += b"\x00" + bytes([n])
65 | n = 0
66 |
67 | r += bytes([i])
68 |
69 | return base64.urlsafe_b64encode(r).decode().rstrip("=")
70 |
71 |
72 |
73 |
74 | def encode_file_ref(file_ref: bytes) -> str:
75 | return base64.urlsafe_b64encode(file_ref).decode().rstrip("=")
76 |
77 |
78 |
79 | def unpack_new_file_id(new_file_id):
80 | """Return file_id, file_ref"""
81 | decoded = FileId.decode(new_file_id)
82 | file_id = encode_file_id(
83 | pack(
84 | "