├── Procfile
├── WebStreamer
├── utils
│ ├── __init__.py
│ ├── human_readable.py
│ ├── keepalive.py
│ ├── broadcast_helper.py
│ ├── time_format.py
│ ├── database.py
│ └── custom_dl.py
├── __init__.py
├── server
│ ├── __init__.py
│ └── stream_routes.py
├── bot
│ ├── __init__.py
│ └── plugins
│ │ ├── admin.py
│ │ ├── stream.py
│ │ └── start.py
├── vars.py
└── __main__.py
├── README.md
├── requirements.txt
└── app.json
/Procfile:
--------------------------------------------------------------------------------
1 | web: python -m WebStreamer
2 |
--------------------------------------------------------------------------------
/WebStreamer/utils/__init__.py:
--------------------------------------------------------------------------------
1 | #ALBINPRAVEEN
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Filetolinkbot
2 | A telegram bot that converts file to a link
3 |
--------------------------------------------------------------------------------
/WebStreamer/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import time
4 | StartTime = time.time()
5 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyrogram
2 | tgcrypto
3 | aiohttp
4 | python-dotenv
5 | motor
6 | aiofiles
7 | dnspython
8 | apscheduler
9 | requests
10 |
--------------------------------------------------------------------------------
/WebStreamer/server/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | from aiohttp import web
3 | from .stream_routes import routes
4 |
5 |
6 | async def web_server():
7 | web_app = web.Application(client_max_size=30000000)
8 | web_app.add_routes(routes)
9 | return web_app
10 |
--------------------------------------------------------------------------------
/WebStreamer/bot/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | from pyrogram import Client
3 | from ..vars import Var
4 |
5 | StreamBot = Client(
6 | session_name='Web Streamer',
7 | api_id=Var.API_ID,
8 | api_hash=Var.API_HASH,
9 | bot_token=Var.BOT_TOKEN,
10 | sleep_threshold=Var.SLEEP_THRESHOLD,
11 | workers=Var.WORKERS
12 | )
--------------------------------------------------------------------------------
/WebStreamer/utils/human_readable.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | def humanbytes(size):
4 |
5 | if not size:
6 | return ""
7 | power = 2**10
8 | n = 0
9 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'}
10 | while size > power:
11 | size /= power
12 | n += 1
13 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B'
--------------------------------------------------------------------------------
/WebStreamer/utils/keepalive.py:
--------------------------------------------------------------------------------
1 | # Bot Sleeping
2 |
3 | import logging
4 | import requests
5 | from ..vars import Var
6 | def ping_server():
7 | k = requests.get(f'https://ping-pong-sn.herokuapp.com/pingback?link={Var.URL}').json()
8 | if not k.get('error'):
9 | logging.info('KeepAliveService: Pinged {} with status {}'.format(Var.FQDN, k.get('Status')))
10 | else:
11 | logging.error('Couldn\'t Ping the Server!')
12 |
--------------------------------------------------------------------------------
/WebStreamer/utils/broadcast_helper.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import asyncio
4 | import traceback
5 | from pyrogram.errors import FloodWait, InputUserDeactivated, UserIsBlocked, PeerIdInvalid
6 |
7 |
8 | async def send_msg(user_id, message):
9 | try:
10 | await message.forward(chat_id=user_id)
11 | return 200, None
12 | except FloodWait as e:
13 | await asyncio.sleep(e.x)
14 | return send_msg(user_id, message)
15 | except InputUserDeactivated:
16 | return 400, f"{user_id} : deactivated\n"
17 | except UserIsBlocked:
18 | return 400, f"{user_id} : blocked the bot\n"
19 | except PeerIdInvalid:
20 | return 400, f"{user_id} : user id invalid\n"
21 | except Exception as e:
22 | return 500, f"{user_id} : {traceback.format_exc()}\n"
--------------------------------------------------------------------------------
/WebStreamer/utils/time_format.py:
--------------------------------------------------------------------------------
1 | # Bot Uptime
2 |
3 | def get_readable_time(seconds: int) -> str:
4 | count = 0
5 | readable_time = ""
6 | time_list = []
7 | time_suffix_list = ["s", "m", "h", " days"]
8 | while count < 4:
9 | count += 1
10 | if count < 3:
11 | remainder, result = divmod(seconds, 60)
12 | else:
13 | remainder, result = divmod(seconds, 24)
14 | if seconds == 0 and remainder == 0:
15 | break
16 | time_list.append(int(result))
17 | seconds = int(remainder)
18 | for x in range(len(time_list)):
19 | time_list[x] = str(time_list[x]) + time_suffix_list[x]
20 | if len(time_list) == 4:
21 | readable_time += time_list.pop() + ", "
22 | time_list.reverse()
23 | readable_time += ": ".join(time_list)
24 | return readable_time
25 |
--------------------------------------------------------------------------------
/WebStreamer/utils/database.py:
--------------------------------------------------------------------------------
1 | # (c) @AbirHasan2005
2 |
3 | import datetime
4 | import motor.motor_asyncio
5 |
6 |
7 | class Database:
8 | def __init__(self, uri, database_name):
9 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri)
10 | self.db = self._client[database_name]
11 | self.col = self.db.users
12 |
13 | def new_user(self, id):
14 | return dict(
15 | id=id,
16 | join_date=datetime.date.today().isoformat()
17 | )
18 |
19 | async def add_user(self, id):
20 | user = self.new_user(id)
21 | await self.col.insert_one(user)
22 |
23 | async def is_user_exist(self, id):
24 | user = await self.col.find_one({'id': int(id)})
25 | return True if user else False
26 |
27 | async def total_users_count(self):
28 | count = await self.col.count_documents({})
29 | return count
30 |
31 | async def get_all_users(self):
32 | all_users = self.col.find({})
33 | return all_users
34 |
35 | async def delete_user(self, user_id):
36 | await self.col.delete_many({'id': int(user_id)})
37 |
--------------------------------------------------------------------------------
/WebStreamer/vars.py:
--------------------------------------------------------------------------------
1 | \
2 | from os import getenv, environ
3 | from dotenv import load_dotenv
4 |
5 | load_dotenv()
6 |
7 |
8 | class Var(object):
9 | API_ID = int(getenv('API_ID'))
10 | API_HASH = str(getenv('API_HASH'))
11 | BOT_TOKEN = str(getenv('BOT_TOKEN'))
12 | SESSION_NAME = str(getenv('SESSION_NAME', 'F2LxBot'))
13 | SLEEP_THRESHOLD = int(getenv('SLEEP_THRESHOLD', '60'))
14 | WORKERS = int(getenv('WORKERS', '4'))
15 | BIN_CHANNEL = int(getenv('BIN_CHANNEL'))
16 | PORT = int(getenv('PORT', 8080))
17 | BIND_ADRESS = str(getenv('WEB_SERVER_BIND_ADDRESS', '0.0.0.0'))
18 | OWNER_ID = int(getenv('OWNER_ID', '808381056'))
19 | NO_PORT = bool(getenv('NO_PORT', False))
20 | APP_NAME = None
21 | if 'DYNO' in environ:
22 | ON_HEROKU = True
23 | APP_NAME = str(getenv('APP_NAME'))
24 | else:
25 | ON_HEROKU = False
26 | FQDN = str(getenv('FQDN', BIND_ADRESS)) if not ON_HEROKU or getenv('FQDN') else APP_NAME+'.herokuapp.com'
27 | URL = "https://{}/".format(FQDN) if ON_HEROKU or NO_PORT else \
28 | "http://{}:{}/".format(FQDN, PORT)
29 | DATABASE_URL = str(getenv('DATABASE_URL'))
30 | UPDATES_CHANNEL = str(getenv('UPDATES_CHANNEL', None))
31 | BANNED_CHANNELS = list(set(int(x) for x in str(getenv("BANNED_CHANNELS", "-123456789")).split()))
32 |
--------------------------------------------------------------------------------
/WebStreamer/server/stream_routes.py:
--------------------------------------------------------------------------------
1 | import time
2 | import math
3 | import logging
4 | import secrets
5 | import mimetypes
6 | from ..vars import Var
7 | from aiohttp import web
8 | from ..bot import StreamBot
9 | from WebStreamer import StartTime
10 | from ..utils.custom_dl import TGCustomYield, chunk_size, offset_fix
11 | from ..utils.time_format import get_readable_time
12 | routes = web.RouteTableDef()
13 |
14 |
15 | @routes.get("/", allow_head=True)
16 | async def root_route_handler(request):
17 | return web.json_response({"status": "running",
18 | "maintained_by": "ALBIN PRAVEEN",
19 | "uptime": get_readable_time(time.time() - StartTime),
20 | "telegram_bot": '@'+(await StreamBot.get_me()).username})
21 |
22 |
23 | @routes.get("/{message_id}")
24 | async def stream_handler(request):
25 | try:
26 | message_id = int(request.match_info['message_id'])
27 | return await media_streamer(request, message_id)
28 | except ValueError as e:
29 | logging.error(e)
30 | raise web.HTTPNotFound
31 |
32 |
33 | async def media_streamer(request, message_id: int):
34 | range_header = request.headers.get('Range', 0)
35 | media_msg = await StreamBot.get_messages(Var.BIN_CHANNEL, message_id)
36 | file_properties = await TGCustomYield().generate_file_properties(media_msg)
37 | file_size = file_properties.file_size
38 |
39 | if range_header:
40 | from_bytes, until_bytes = range_header.replace('bytes=', '').split('-')
41 | from_bytes = int(from_bytes)
42 | until_bytes = int(until_bytes) if until_bytes else file_size - 1
43 | else:
44 | from_bytes = request.http_range.start or 0
45 | until_bytes = request.http_range.stop or file_size - 1
46 |
47 | req_length = until_bytes - from_bytes
48 |
49 | new_chunk_size = await chunk_size(req_length)
50 | offset = await offset_fix(from_bytes, new_chunk_size)
51 | first_part_cut = from_bytes - offset
52 | last_part_cut = (until_bytes % new_chunk_size) + 1
53 | part_count = math.ceil(req_length / new_chunk_size)
54 | body = TGCustomYield().yield_file(media_msg, offset, first_part_cut, last_part_cut, part_count,
55 | new_chunk_size)
56 |
57 | file_name = file_properties.file_name if file_properties.file_name \
58 | else f"{secrets.token_hex(2)}.jpeg"
59 | mime_type = file_properties.mime_type if file_properties.mime_type \
60 | else f"{mimetypes.guess_type(file_name)}"
61 |
62 | return_resp = web.Response(
63 | status=206 if range_header else 200,
64 | body=body,
65 | headers={
66 | "Content-Type": mime_type,
67 | "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
68 | "Content-Disposition": f'attachment; filename="{file_name}"',
69 | "Accept-Ranges": "bytes",
70 | }
71 | )
72 |
73 | if return_resp.status == 200:
74 | return_resp.headers.add("Content-Length", str(file_size))
75 |
76 | return return_resp
77 |
--------------------------------------------------------------------------------
/WebStreamer/__main__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import glob
4 | import asyncio
5 | import logging
6 | import importlib
7 | from pathlib import Path
8 | from pyrogram import idle
9 | from .bot import StreamBot
10 | from .vars import Var
11 | from aiohttp import web
12 | from .server import web_server
13 | from .utils.keepalive import ping_server
14 | from apscheduler.schedulers.background import BackgroundScheduler
15 |
16 | logging.basicConfig(
17 | level=logging.INFO,
18 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
19 | )
20 | logging.getLogger("pyrogram").setLevel(logging.WARNING)
21 | logging.getLogger("apscheduler").setLevel(logging.WARNING)
22 |
23 | ppath = "WebStreamer/bot/plugins/*.py"
24 | files = glob.glob(ppath)
25 |
26 | loop = asyncio.get_event_loop()
27 |
28 |
29 | async def start_services():
30 | print('\n')
31 | print('------------------- Initalizing Telegram Bot -------------------')
32 | await StreamBot.start()
33 | print('----------------------------- DONE -----------------------------')
34 | print('\n')
35 | print('--------------------------- Importing ---------------------------')
36 | for name in files:
37 | with open(name) as a:
38 | patt = Path(a.name)
39 | plugin_name = patt.stem.replace(".py", "")
40 | plugins_dir = Path(f"WebStreamer/bot/plugins/{plugin_name}.py")
41 | import_path = ".plugins.{}".format(plugin_name)
42 | spec = importlib.util.spec_from_file_location(import_path, plugins_dir)
43 | load = importlib.util.module_from_spec(spec)
44 | spec.loader.exec_module(load)
45 | sys.modules["WebStreamer.bot.plugins." + plugin_name] = load
46 | print("Imported => " + plugin_name)
47 | if Var.ON_HEROKU:
48 | print('------------------ Starting Keep Alive Service ------------------')
49 | print('\n')
50 | scheduler = BackgroundScheduler()
51 | scheduler.add_job(ping_server, "interval", seconds=1200)
52 | scheduler.start()
53 | print('-------------------- Initalizing Web Server --------------------')
54 | app = web.AppRunner(await web_server())
55 | await app.setup()
56 | bind_address = "0.0.0.0" if Var.ON_HEROKU else Var.FQDN
57 | await web.TCPSite(app, bind_address, Var.PORT).start()
58 | print('----------------------------- DONE -----------------------------')
59 | print('\n')
60 | print('----------------------- Service Started -----------------------')
61 | print(' bot =>> {}'.format((await StreamBot.get_me()).first_name))
62 | print(' server ip =>> {}:{}'.format(bind_address, Var.PORT))
63 | if Var.ON_HEROKU:
64 | print(' app runnng on =>> {}'.format(Var.FQDN))
65 | print('---------------------------------------------------------------')
66 | await idle()
67 |
68 | if __name__ == '__main__':
69 | try:
70 | loop.run_until_complete(start_services())
71 | except KeyboardInterrupt:
72 | logging.info('----------------------- Service Stopped -----------------------')
73 |
--------------------------------------------------------------------------------
/WebStreamer/bot/plugins/admin.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 | import time
4 | import string
5 | import random
6 | import asyncio
7 | import aiofiles
8 | import datetime
9 | from WebStreamer.utils.broadcast_helper import send_msg
10 | from WebStreamer.utils.database import Database
11 | from WebStreamer.bot import StreamBot
12 | from WebStreamer.vars import Var
13 | from pyrogram import filters, Client
14 | from pyrogram.types import Message
15 | db = Database(Var.DATABASE_URL, Var.SESSION_NAME)
16 | broadcast_ids = {}
17 |
18 |
19 | @StreamBot.on_message(filters.command("status") & filters.private & filters.user(Var.OWNER_ID) & ~filters.edited)
20 | async def sts(c: Client, m: Message):
21 | total_users = await db.total_users_count()
22 | await m.reply_text(text=f"**Total Users in DB:** `{total_users}`", parse_mode="Markdown", quote=True)
23 |
24 |
25 | @StreamBot.on_message(filters.command("broadcast") & filters.private & filters.user(Var.OWNER_ID) & filters.reply & ~filters.edited)
26 | async def broadcast_(c, m):
27 | all_users = await db.get_all_users()
28 | broadcast_msg = m.reply_to_message
29 | while True:
30 | broadcast_id = ''.join([random.choice(string.ascii_letters) for i in range(3)])
31 | if not broadcast_ids.get(broadcast_id):
32 | break
33 | out = await m.reply_text(
34 | text=f"Broadcast initiated! You will be notified with log file when all the users are notified."
35 | )
36 | start_time = time.time()
37 | total_users = await db.total_users_count()
38 | done = 0
39 | failed = 0
40 | success = 0
41 | broadcast_ids[broadcast_id] = dict(
42 | total=total_users,
43 | current=done,
44 | failed=failed,
45 | success=success
46 | )
47 | async with aiofiles.open('broadcast.txt', 'w') as broadcast_log_file:
48 | async for user in all_users:
49 | sts, msg = await send_msg(
50 | user_id=int(user['id']),
51 | message=broadcast_msg
52 | )
53 | if msg is not None:
54 | await broadcast_log_file.write(msg)
55 | if sts == 200:
56 | success += 1
57 | else:
58 | failed += 1
59 | if sts == 400:
60 | await db.delete_user(user['id'])
61 | done += 1
62 | if broadcast_ids.get(broadcast_id) is None:
63 | break
64 | else:
65 | broadcast_ids[broadcast_id].update(
66 | dict(
67 | current=done,
68 | failed=failed,
69 | success=success
70 | )
71 | )
72 | if broadcast_ids.get(broadcast_id):
73 | broadcast_ids.pop(broadcast_id)
74 | completed_in = datetime.timedelta(seconds=int(time.time() - start_time))
75 | await asyncio.sleep(3)
76 | await out.delete()
77 | if failed == 0:
78 | await m.reply_text(
79 | text=f"broadcast completed in `{completed_in}`\n\nTotal users {total_users}.\nTotal done {done}, {success} success and {failed} failed.",
80 | quote=True
81 | )
82 | else:
83 | await m.reply_document(
84 | document='broadcast.txt',
85 | caption=f"broadcast completed in `{completed_in}`\n\nTotal users {total_users}.\nTotal done {done}, {success} success and {failed} failed.",
86 | quote=True
87 | )
88 | os.remove('broadcast.txt')
89 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Filetolinkbot",
3 | "description": "A Pyrogram Telegram bot to Stream Telegram files to web. @i_am_albin_praveen",
4 | "keywords": [
5 | "telegram",
6 | "stream",
7 | "web",
8 | "pyrogram",
9 | "aiohttp",
10 | "python",
11 | "plugin",
12 | "modular",
13 | "media"
14 | ],
15 | "repository": "https://github.com/ALBINPRAVEEN/Filetolinkbot",
16 | "success_url": "/",
17 | "logo": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRLYL8tucdc2Ntt8MkRmxwPxejRCCWiEt_ch5xfWk12C49EcOadHjU_ToeyMf5pBMaWIZA&usqp=CAU",
18 | "website": "albinpraveen.ml",
19 | "env": {
20 | "ENV": {
21 | "description": "Set this to True if you don't want to crash the bot",
22 | "value": "True"
23 | },
24 | "APP_NAME": {
25 | "description": "Copy-Paste the app name that you just typed above."
26 | },
27 | "API_ID": {
28 | "description": "Get this value from https://my.telegram.org"
29 | },
30 | "API_HASH": {
31 | "description": "Get this value from https://my.telegram.org"
32 | },
33 | "BOT_TOKEN": {
34 | "description": "Get this value from @BotFather"
35 | },
36 | "BIN_CHANNEL": {
37 | "description": "The BIN Channel ID. Read the readme for more info about this var"
38 |
39 | },
40 | "DATABASE_URL": {
41 | "description": "MongoDB URI for saving User IDs when they first Start the Bot. We will use that for Broadcasting to them. I will try to add more features related with Database. If you need help to get the URI you can ask in Support Group: https://t.me/i_am_albin_praveen"
42 | },
43 | "OWNER_ID": {
44 | "description": "Your Telegram User ID"
45 | },
46 | "BANNED_CHANNELS": {
47 | "description": "Put IDs of Banned Channels where bot will not work. You can add multiple IDs & separate with Space.",
48 | "required": false
49 | },
50 | "UPDATES_CHANNEL": {
51 | "description": "Put a Public Channel Username, so every user have to Join that channel to use the bot. Must add bot to channel as Admin to work properly.",
52 | "required": false
53 |
54 | },
55 | "SLEEP_THRESHOLD": {
56 | "description": "Floodwait Sleep timer. Read the readme for more info about this var",
57 | "required": false
58 | },
59 | "WORKERS": {
60 | "description": "No. of workers that is to be assigned. Read the readme for more info about this var",
61 | "required": false
62 | },
63 | "PORT": {
64 | "description": "Port that you want your webapp to be listened to. Read the readme for more info about this var",
65 | "required": false
66 | },
67 | "NO_PORT": {
68 | "description": "If you don't want your port to be displayed. Read the readme for more info about this var",
69 | "value": "False",
70 | "required": false
71 | },
72 | "BIND_ADRESS": {
73 | "description": "Read the readme for more info about this var",
74 | "required": false
75 | },
76 | "FQDN": {
77 | "description": "Read the readme for more info about this var",
78 | "required": false
79 | },
80 | "SESSION_NAME": {
81 | "description": " Session Name for Bot [ Add ALBINPRAVEEN ]",
82 | "required": false
83 | }
84 | },
85 | "buildpacks": [{
86 | "url": "heroku/python"
87 | }],
88 | "formation": {
89 | "web": {
90 | "quantity": 1,
91 | "size": "free"
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/WebStreamer/bot/plugins/stream.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import asyncio
4 | from WebStreamer.bot import StreamBot
5 | from WebStreamer.utils.database import Database
6 | from WebStreamer.utils.human_readable import humanbytes
7 | from WebStreamer.vars import Var
8 | from pyrogram import filters, Client
9 | from pyrogram.errors import FloodWait, UserNotParticipant
10 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
11 | db = Database(Var.DATABASE_URL, Var.SESSION_NAME)
12 |
13 |
14 | @StreamBot.on_message(filters.private & (filters.document | filters.video | filters.audio) & ~filters.edited, group=4)
15 | async def private_receive_handler(c: Client, m: Message):
16 | if not await db.is_user_exist(m.from_user.id):
17 | await db.add_user(m.from_user.id)
18 | await c.send_message(
19 | Var.BIN_CHANNEL,
20 | f"Nᴇᴡ Usᴇʀ Jᴏɪɴᴇᴅ : \n\nNᴀᴍᴇ : [{m.from_user.first_name}](tg://user?id={m.from_user.id}) Sᴛᴀʀᴛᴇᴅ Yᴏᴜʀ Bᴏᴛ !!"
21 | )
22 | if Var.UPDATES_CHANNEL != "None":
23 | try:
24 | user = await c.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id)
25 | if user.status == "kicked":
26 | await c.send_message(
27 | chat_id=m.chat.id,
28 | text="__Sᴏʀʀʏ Sɪʀ, Yᴏᴜ ᴀʀᴇ Bᴀɴɴᴇᴅ ᴛᴏ ᴜsᴇ ᴍᴇ.__\n\n **Cᴏɴᴛᴀᴄᴛ Dᴇᴠᴇʟᴏᴘᴇʀ @i_am_albin_praveen Tʜᴇʏ Wɪʟʟ Hᴇʟᴘ Yᴏᴜ**",
29 | parse_mode="markdown",
30 | disable_web_page_preview=True
31 | )
32 | return
33 | except UserNotParticipant:
34 | await c.send_message(
35 | chat_id=m.chat.id,
36 | text="""Jᴏɪɴ ᴍʏ ᴜᴘᴅᴀᴛᴇ ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜꜱᴇ ᴍᴇ 🔐""",
37 | reply_markup=InlineKeyboardMarkup(
38 | [[ InlineKeyboardButton("Jᴏɪɴ ɴᴏᴡ 🔓", url=f"https://t.me/{Var.UPDATES_CHANNEL}") ]]
39 | ),
40 | parse_mode="HTML"
41 | )
42 | return
43 | except Exception:
44 | await c.send_message(
45 | chat_id=m.chat.id,
46 | text="**Sᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ Wʀᴏɴɢ. Cᴏɴᴛᴀᴄᴛ ᴍʏ ʙᴏss** @i_am_albin_praveen",
47 | parse_mode="markdown",
48 | disable_web_page_preview=True)
49 | return
50 | try:
51 | log_msg = await m.forward(chat_id=Var.BIN_CHANNEL)
52 | stream_link = "https://{}/{}".format(Var.FQDN, log_msg.message_id) if Var.ON_HEROKU or Var.NO_PORT else \
53 | "http://{}:{}/{}".format(Var.FQDN,
54 | Var.PORT,
55 | log_msg.message_id)
56 | file_size = None
57 | if m.video:
58 | file_size = f"{humanbytes(m.video.file_size)}"
59 | elif m.document:
60 | file_size = f"{humanbytes(m.document.file_size)}"
61 | elif m.audio:
62 | file_size = f"{humanbytes(m.audio.file_size)}"
63 |
64 | file_name = None
65 | if m.video:
66 | file_name = f"{m.video.file_name}"
67 | elif m.document:
68 | file_name = f"{m.document.file_name}"
69 | elif m.audio:
70 | file_name = f"{m.audio.file_name}"
71 |
72 | msg_text ="""
73 | 𝗬𝗼𝘂𝗿 𝗟𝗶𝗻𝗸 𝗚𝗲𝗻𝗲𝗿𝗮𝘁𝗲𝗱 !\n
74 | 📂 Fɪʟᴇ ɴᴀᴍᴇ : {}\n
75 | 📦 Fɪʟᴇ ꜱɪᴢᴇ : {}\n
76 | 📥 Dᴏᴡɴʟᴏᴀᴅ : {}\n
77 | 🚸 Nᴏᴛᴇ : Tʜɪs ᴘᴇʀᴍᴀɴᴇɴᴛ Lɪɴᴋ, Nᴏᴛ Exᴘɪʀᴇᴅ\n
78 | © @i_am_albin_praveen """
79 |
80 | await log_msg.reply_text(text=f"**RᴇQᴜᴇꜱᴛᴇᴅ ʙʏ :** [{m.from_user.first_name}](tg://user?id={m.from_user.id})\n**Uꜱᴇʀ ɪᴅ :** `{m.from_user.id}`\n**Dᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ :** {stream_link}", disable_web_page_preview=True, parse_mode="Markdown", quote=True)
81 | await m.reply_text(
82 | text=msg_text.format(file_name, file_size, stream_link),
83 | parse_mode="HTML",
84 | disable_web_page_preview=True,
85 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Dᴏᴡɴʟᴏᴀᴅ ɴᴏᴡ 📥", url=stream_link)]]),
86 | quote=True
87 | )
88 | except FloodWait as e:
89 | print(f"Sleeping for {str(e.x)}s")
90 | await asyncio.sleep(e.x)
91 | await c.send_message(chat_id=Var.BIN_CHANNEL, text=f"Gᴏᴛ FʟᴏᴏᴅWᴀɪᴛ ᴏғ {str(e.x)}s from [{m.from_user.first_name}](tg://user?id={m.from_user.id})\n\n**𝚄𝚜𝚎𝚛 𝙸𝙳 :** `{str(m.from_user.id)}`", disable_web_page_preview=True, parse_mode="Markdown")
92 |
93 |
94 | @StreamBot.on_message(filters.channel & (filters.document | filters.video) & ~filters.edited, group=-1)
95 | async def channel_receive_handler(bot, broadcast):
96 | if int(broadcast.chat.id) in Var.BANNED_CHANNELS:
97 | await bot.leave_chat(broadcast.chat.id)
98 | return
99 | try:
100 | log_msg = await broadcast.forward(chat_id=Var.BIN_CHANNEL)
101 | stream_link = "https://{}/{}".format(Var.FQDN, log_msg.message_id) if Var.ON_HEROKU or Var.NO_PORT else \
102 | "http://{}:{}/{}".format(Var.FQDN,
103 | Var.PORT,
104 | log_msg.message_id)
105 | await log_msg.reply_text(
106 | text=f"**Cʜᴀɴɴᴇʟ Nᴀᴍᴇ:** `{broadcast.chat.title}`\n**Cʜᴀɴɴᴇʟ ID:** `{broadcast.chat.id}`\n**Rᴇǫᴜᴇsᴛ ᴜʀʟ:** {stream_link}",
107 | quote=True,
108 | parse_mode="Markdown"
109 | )
110 | await bot.edit_message_reply_markup(
111 | chat_id=broadcast.chat.id,
112 | message_id=broadcast.message_id,
113 | reply_markup=InlineKeyboardMarkup(
114 | [[InlineKeyboardButton("Dᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ 📥", url=stream_link)]])
115 | )
116 | except FloodWait as w:
117 | print(f"Sleeping for {str(w.x)}s")
118 | await asyncio.sleep(w.x)
119 | await bot.send_message(chat_id=Var.BIN_CHANNEL,
120 | text=f"Gᴏᴛ FʟᴏᴏᴅWᴀɪᴛ ᴏғ {str(w.x)}s from {broadcast.chat.title}\n\n**Cʜᴀɴɴᴇʟ ID:** `{str(broadcast.chat.id)}`",
121 | disable_web_page_preview=True, parse_mode="Markdown")
122 | except Exception as e:
123 | await bot.send_message(chat_id=Var.BIN_CHANNEL, text=f"**#ᴇʀʀᴏʀ_ᴛʀᴀᴄᴇʙᴀᴄᴋ:** `{e}`", disable_web_page_preview=True, parse_mode="Markdown")
124 | print(f"Cᴀɴ'ᴛ Eᴅɪᴛ Bʀᴏᴀᴅᴄᴀsᴛ Mᴇssᴀɢᴇ!\nEʀʀᴏʀ: {e}")
125 |
--------------------------------------------------------------------------------
/WebStreamer/utils/custom_dl.py:
--------------------------------------------------------------------------------
1 |
2 | import math
3 | from typing import Union
4 | from pyrogram.types import Message
5 | from ..bot import StreamBot
6 | from pyrogram import Client, utils, raw
7 | from pyrogram.session import Session, Auth
8 | from pyrogram.errors import AuthBytesInvalid
9 | from pyrogram.file_id import FileId, FileType, ThumbnailSource
10 |
11 |
12 | async def chunk_size(length):
13 | return 2 ** max(min(math.ceil(math.log2(length / 1024)), 10), 2) * 1024
14 |
15 |
16 | async def offset_fix(offset, chunksize):
17 | offset -= offset % chunksize
18 | return offset
19 |
20 |
21 | class TGCustomYield:
22 | def __init__(self):
23 |
24 | self.main_bot = StreamBot
25 |
26 | @staticmethod
27 | async def generate_file_properties(msg: Message):
28 | error_message = "This message doesn't contain any downloadable media"
29 | available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note")
30 |
31 | if isinstance(msg, Message):
32 | for kind in available_media:
33 | media = getattr(msg, kind, None)
34 |
35 | if media is not None:
36 | break
37 | else:
38 | raise ValueError(error_message)
39 | else:
40 | media = msg
41 |
42 | if isinstance(media, str):
43 | file_id_str = media
44 | else:
45 | file_id_str = media.file_id
46 |
47 | file_id_obj = FileId.decode(file_id_str)
48 |
49 | # The below lines are added to avoid a break in routes.py
50 | setattr(file_id_obj, "file_size", getattr(media, "file_size", 0))
51 | setattr(file_id_obj, "mime_type", getattr(media, "mime_type", ""))
52 | setattr(file_id_obj, "file_name", getattr(media, "file_name", ""))
53 |
54 | return file_id_obj
55 |
56 | async def generate_media_session(self, client: Client, msg: Message):
57 | data = await self.generate_file_properties(msg)
58 |
59 | media_session = client.media_sessions.get(data.dc_id, None)
60 |
61 | if media_session is None:
62 | if data.dc_id != await client.storage.dc_id():
63 | media_session = Session(
64 | client, data.dc_id, await Auth(client, data.dc_id, await client.storage.test_mode()).create(),
65 | await client.storage.test_mode(), is_media=True
66 | )
67 | await media_session.start()
68 |
69 | for _ in range(3):
70 | exported_auth = await client.send(
71 | raw.functions.auth.ExportAuthorization(
72 | dc_id=data.dc_id
73 | )
74 | )
75 |
76 | try:
77 | await media_session.send(
78 | raw.functions.auth.ImportAuthorization(
79 | id=exported_auth.id,
80 | bytes=exported_auth.bytes
81 | )
82 | )
83 | except AuthBytesInvalid:
84 | continue
85 | else:
86 | break
87 | else:
88 | await media_session.stop()
89 | raise AuthBytesInvalid
90 | else:
91 | media_session = Session(
92 | client, data.dc_id, await client.storage.auth_key(),
93 | await client.storage.test_mode(), is_media=True
94 | )
95 | await media_session.start()
96 |
97 | client.media_sessions[data.dc_id] = media_session
98 |
99 | return media_session
100 |
101 | @staticmethod
102 | async def get_location(file_id: FileId):
103 | file_type = file_id.file_type
104 |
105 | if file_type == FileType.CHAT_PHOTO:
106 | if file_id.chat_id > 0:
107 | peer = raw.types.InputPeerUser(
108 | user_id=file_id.chat_id,
109 | access_hash=file_id.chat_access_hash
110 | )
111 | else:
112 | if file_id.chat_access_hash == 0:
113 | peer = raw.types.InputPeerChat(
114 | chat_id=-file_id.chat_id
115 | )
116 | else:
117 | peer = raw.types.InputPeerChannel(
118 | channel_id=utils.get_channel_id(file_id.chat_id),
119 | access_hash=file_id.chat_access_hash
120 | )
121 |
122 | location = raw.types.InputPeerPhotoFileLocation(
123 | peer=peer,
124 | volume_id=file_id.volume_id,
125 | local_id=file_id.local_id,
126 | big=file_id.thumbnail_source == ThumbnailSource.CHAT_PHOTO_BIG
127 | )
128 | elif file_type == FileType.PHOTO:
129 | location = raw.types.InputPhotoFileLocation(
130 | id=file_id.media_id,
131 | access_hash=file_id.access_hash,
132 | file_reference=file_id.file_reference,
133 | thumb_size=file_id.thumbnail_size
134 | )
135 | else:
136 | location = raw.types.InputDocumentFileLocation(
137 | id=file_id.media_id,
138 | access_hash=file_id.access_hash,
139 | file_reference=file_id.file_reference,
140 | thumb_size=file_id.thumbnail_size
141 | )
142 |
143 | return location
144 |
145 | async def yield_file(self, media_msg: Message, offset: int, first_part_cut: int,
146 | last_part_cut: int, part_count: int, chunk_size: int) -> Union[str, None]: #pylint: disable=unsubscriptable-object
147 | client = self.main_bot
148 | data = await self.generate_file_properties(media_msg)
149 | media_session = await self.generate_media_session(client, media_msg)
150 |
151 | current_part = 1
152 |
153 | location = await self.get_location(data)
154 |
155 | r = await media_session.send(
156 | raw.functions.upload.GetFile(
157 | location=location,
158 | offset=offset,
159 | limit=chunk_size
160 | ),
161 | )
162 |
163 | if isinstance(r, raw.types.upload.File):
164 | while current_part <= part_count:
165 | chunk = r.bytes
166 | if not chunk:
167 | break
168 | offset += chunk_size
169 | if part_count == 1:
170 | yield chunk[first_part_cut:last_part_cut]
171 | break
172 | if current_part == 1:
173 | yield chunk[first_part_cut:]
174 | if 1 < current_part <= part_count:
175 | yield chunk
176 |
177 | r = await media_session.send(
178 | raw.functions.upload.GetFile(
179 | location=location,
180 | offset=offset,
181 | limit=chunk_size
182 | ),
183 | )
184 |
185 | current_part += 1
186 |
187 | async def download_as_bytesio(self, media_msg: Message):
188 | client = self.main_bot
189 | data = await self.generate_file_properties(media_msg)
190 | media_session = await self.generate_media_session(client, media_msg)
191 |
192 | location = await self.get_location(data)
193 |
194 | limit = 1024 * 1024
195 | offset = 0
196 |
197 | r = await media_session.send(
198 | raw.functions.upload.GetFile(
199 | location=location,
200 | offset=offset,
201 | limit=limit
202 | )
203 | )
204 |
205 | if isinstance(r, raw.types.upload.File):
206 | m_file = []
207 | # m_file.name = file_name
208 | while True:
209 | chunk = r.bytes
210 |
211 | if not chunk:
212 | break
213 |
214 | m_file.append(chunk)
215 |
216 | offset += limit
217 |
218 | r = await media_session.send(
219 | raw.functions.upload.GetFile(
220 | location=location,
221 | offset=offset,
222 | limit=limit
223 | )
224 | )
225 |
226 | return m_file
--------------------------------------------------------------------------------
/WebStreamer/bot/plugins/start.py:
--------------------------------------------------------------------------------
1 | # © @i_am_albin_praveen [ Telegram ]
2 |
3 | from WebStreamer.bot import StreamBot
4 | from WebStreamer.vars import Var
5 | from WebStreamer.utils.human_readable import humanbytes
6 | from WebStreamer.utils.database import Database
7 | from pyrogram import filters
8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
9 | from pyrogram.errors import UserNotParticipant
10 | db = Database(Var.DATABASE_URL, Var.SESSION_NAME)
11 |
12 | START_TEXT = """
13 | 👋 Hᴇʏ,{}\n
14 | I'ᴍ Tᴇʟᴇɢʀᴀᴍ Fɪʟᴇs Sᴛʀᴇᴀᴍɪɴɢ Bᴏᴛ ᴀs ᴡᴇʟʟ Dɪʀᴇᴄᴛ Lɪɴᴋs Gᴇɴᴇʀᴀᴛᴇ\n
15 | Cʟɪᴄᴋ ᴏɴ Hᴇʟᴘ ᴛᴏ ɢᴇᴛ ᴍᴏʀᴇ ɪɴғᴏʀᴍᴀᴛɪᴏɴ\n
16 | 𝗪𝗔𝗥𝗡𝗜𝗡𝗚 🚸
17 | 🔞 Pʀᴏɴ ᴄᴏɴᴛᴇɴᴛꜱ ʟᴇᴀᴅꜱ ᴛᴏ ᴘᴇʀᴍᴀɴᴇɴᴛ ʙᴀɴ ʏᴏᴜ.\n\n
18 | 🍃 Bᴏᴛ Mᴀɪɴᴛᴀɪɴᴇᴅ Bʏ :@i_am_albin_praveen"""
19 |
20 | HELP_TEXT = """
21 | - Sᴇɴᴅ ᴍᴇ ᴀɴʏ ꜰɪʟᴇ (ᴏʀ) ᴍᴇᴅɪᴀ ꜰʀᴏᴍ ᴛᴇʟᴇɢʀᴀᴍ.
22 | - I ᴡɪʟʟ ᴘʀᴏᴠɪᴅᴇ ᴇxᴛᴇʀɴᴀʟ ᴅɪʀᴇᴄᴛ ᴅᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ !.
23 | - Aᴅᴅ Mᴇ ɪɴ ʏᴏᴜʀ Cʜᴀɴɴᴇʟ Fᴏʀ Dɪʀᴇᴄᴛ Dᴏᴡɴʟᴏᴀᴅ Lɪɴᴋs Bᴜᴛᴛᴏɴ
24 | - Tʜɪs Pᴇʀᴍᴇᴀɴᴛ Lɪɴᴋ Wɪᴛʜ Fᴀsᴛᴇsᴛ Sᴘᴇᴇᴅ\n
25 | 🔸 𝗪𝗔𝗥𝗡𝗜𝗡𝗚 🚸\n
26 | 🔞 Pʀᴏɴ ᴄᴏɴᴛᴇɴᴛꜱ ʟᴇᴀᴅꜱ ᴛᴏ ᴘᴇʀᴍᴀɴᴇɴᴛ ʙᴀɴ ʏᴏᴜ.\n
27 | Cᴏɴᴛᴀᴄᴛ ᴅᴇᴠᴇʟᴏᴘᴇʀ (ᴏʀ) ʀᴇᴘᴏʀᴛ ʙᴜɢꜱ : [ ᴄʟɪᴄᴋ ʜᴇʀᴇ ]"""
28 |
29 | ABOUT_TEXT = """
30 | ⚜ Mʏ ɴᴀᴍᴇ : FileStreamX\n
31 | 🔸Vᴇʀꜱɪᴏɴ : 3.0.1\n
32 | 🔹Sᴏᴜʀᴄᴇ : Cʟɪᴄᴋ Hᴇʀᴇ\n
33 | 🔸GitHub : Fᴏʟʟᴏᴡ\n
34 | 🔹Dᴇᴠᴇʟᴏᴘᴇʀ : ALBIN PRAVEEN\n
35 |
36 | START_BUTTONS = InlineKeyboardMarkup(
37 | [[
38 | InlineKeyboardButton('Hᴇʟᴘ', callback_data='help'),
39 | InlineKeyboardButton('Aʙᴏᴜᴛ', callback_data='about'),
40 | InlineKeyboardButton('Cʟᴏsᴇ', callback_data='close')
41 | ]]
42 | )
43 | HELP_BUTTONS = InlineKeyboardMarkup(
44 | [[
45 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='home'),
46 | InlineKeyboardButton('Aʙᴏᴜᴛ', callback_data='about'),
47 | InlineKeyboardButton('Cʟᴏsᴇ', callback_data='close')
48 | ]]
49 | )
50 | ABOUT_BUTTONS = InlineKeyboardMarkup(
51 | [[
52 | InlineKeyboardButton('Hᴏᴍᴇ', callback_data='home'),
53 | InlineKeyboardButton('Hᴇʟᴘ', callback_data='help'),
54 | InlineKeyboardButton('Cʟᴏsᴇ', callback_data='close')
55 | ]]
56 | )
57 |
58 | @StreamBot.on_callback_query()
59 | async def cb_data(bot, update):
60 | if update.data == "home":
61 | await update.message.edit_text(
62 | text=START_TEXT.format(update.from_user.mention),
63 | disable_web_page_preview=True,
64 | reply_markup=START_BUTTONS
65 | )
66 | elif update.data == "help":
67 | await update.message.edit_text(
68 | text=HELP_TEXT,
69 | disable_web_page_preview=True,
70 | reply_markup=HELP_BUTTONS
71 | )
72 | elif update.data == "about":
73 | await update.message.edit_text(
74 | text=ABOUT_TEXT,
75 | disable_web_page_preview=True,
76 | reply_markup=ABOUT_BUTTONS
77 | )
78 | else:
79 | await update.message.delete()
80 |
81 |
82 | @StreamBot.on_message(filters.command('start') & filters.private & ~filters.edited)
83 | async def start(b, m):
84 | if not await db.is_user_exist(m.from_user.id):
85 | await db.add_user(m.from_user.id)
86 | await b.send_message(
87 | Var.BIN_CHANNEL,
88 | f"**Nᴇᴡ Usᴇʀ Jᴏɪɴᴇᴅ:** \n\n__Mʏ Nᴇᴡ Fʀɪᴇɴᴅ__ [{m.from_user.first_name}](tg://user?id={m.from_user.id}) __Sᴛᴀʀᴛᴇᴅ Yᴏᴜʀ Bᴏᴛ !!__"
89 | )
90 | usr_cmd = m.text.split("_")[-1]
91 | if usr_cmd == "/start":
92 | if Var.UPDATES_CHANNEL != "None":
93 | try:
94 | user = await b.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id)
95 | if user.status == "kicked":
96 | await b.send_message(
97 | chat_id=m.chat.id,
98 | text="__Sᴏʀʀʏ Sɪʀ, Yᴏᴜ ᴀʀᴇ Bᴀɴɴᴇᴅ ᴛᴏ ᴜsᴇ ᴍᴇ. Cᴏɴᴛᴀᴄᴛ ᴛʜᴇ Dᴇᴠᴇʟᴏᴘᴇʀ__\n\n @i_am_albin_praveen **Tʜᴇʏ Wɪʟʟ Hᴇʟᴘ Yᴏᴜ**",
99 | parse_mode="markdown",
100 | disable_web_page_preview=True
101 | )
102 | return
103 | except UserNotParticipant:
104 | await b.send_message(
105 | chat_id=m.chat.id,
106 | text="Jᴏɪɴ ᴍʏ ᴜᴘᴅᴀᴛᴇ ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴍᴇ 🔐",
107 | reply_markup=InlineKeyboardMarkup(
108 | [[
109 | InlineKeyboardButton("Jᴏɪɴ ɴᴏᴡ 🔓", url=f"https://t.me/{Var.UPDATES_CHANNEL}")
110 | ]]
111 | ),
112 | parse_mode="HTML"
113 | )
114 | return
115 | except Exception:
116 | await b.send_message(
117 | chat_id=m.chat.id,
118 | text="Sᴏᴍᴇᴛʜɪɴɢ ᴡʀᴏɴɢ ᴄᴏɴᴛᴀᴄᴛ ᴍʏ ᴅᴇᴠᴇʟᴏᴘᴇʀ [ ᴄʟɪᴄᴋ ʜᴇʀᴇ ]",
119 | parse_mode="HTML",
120 | disable_web_page_preview=True)
121 | return
122 | await m.reply_text(
123 | text=START_TEXT.format(m.from_user.mention),
124 | parse_mode="HTML",
125 | disable_web_page_preview=True,
126 | reply_markup=START_BUTTONS
127 | )
128 |
129 |
130 | else:
131 | if Var.UPDATES_CHANNEL != "None":
132 | try:
133 | user = await b.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id)
134 | if user.status == "kicked":
135 | await b.send_message(
136 | chat_id=m.chat.id,
137 | text="**Sᴏʀʀʏ Sɪʀ, Yᴏᴜ ᴀʀᴇ Bᴀɴɴᴇᴅ ᴛᴏ ᴜsᴇ ᴍᴇ. Qᴜɪᴄᴋʟʏ ᴄᴏɴᴛᴀᴄᴛ** @i_am_albin_praveen",
138 | parse_mode="markdown",
139 | disable_web_page_preview=True
140 | )
141 | return
142 | except UserNotParticipant:
143 | await b.send_message(
144 | chat_id=m.chat.id,
145 | text="**Pʟᴇᴀsᴇ Jᴏɪɴ Mʏ Uᴘᴅᴀᴛᴇs Cʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴛʜɪs Bᴏᴛ**!\n\n**Dᴜᴇ ᴛᴏ Oᴠᴇʀʟᴏᴀᴅ, Oɴʟʏ Cʜᴀɴɴᴇʟ Sᴜʙsᴄʀɪʙᴇʀs ᴄᴀɴ ᴜsᴇ ᴛʜᴇ Bᴏᴛ**!",
146 | reply_markup=InlineKeyboardMarkup(
147 | [[
148 | InlineKeyboardButton("🤖 Jᴏɪɴ Uᴘᴅᴀᴛᴇs Cʜᴀɴɴᴇʟ", url=f"https://t.me/{Var.UPDATES_CHANNEL}")
149 | ]]
150 | ),
151 | parse_mode="markdown"
152 | )
153 | return
154 | except Exception:
155 | await b.send_message(
156 | chat_id=m.chat.id,
157 | text="**Sᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ Wʀᴏɴɢ. Cᴏɴᴛᴀᴄᴛ ᴍᴇ** [ALBIN PRAVEEN](https://t.me/i_am_albin_praveen).",
158 | parse_mode="markdown",
159 | disable_web_page_preview=True)
160 | return
161 |
162 | get_msg = await b.get_messages(chat_id=Var.BIN_CHANNEL, message_ids=int(usr_cmd))
163 |
164 | file_size = None
165 | if get_msg.video:
166 | file_size = f"{humanbytes(get_msg.video.file_size)}"
167 | elif get_msg.document:
168 | file_size = f"{humanbytes(get_msg.document.file_size)}"
169 | elif get_msg.audio:
170 | file_size = f"{humanbytes(get_msg.audio.file_size)}"
171 |
172 | file_name = None
173 | if get_msg.video:
174 | file_name = f"{get_msg.video.file_name}"
175 | elif get_msg.document:
176 | file_name = f"{get_msg.document.file_name}"
177 | elif get_msg.audio:
178 | file_name = f"{get_msg.audio.file_name}"
179 |
180 | stream_link = "https://{}/{}".format(Var.FQDN, get_msg.message_id) if Var.ON_HEROKU or Var.NO_PORT else \
181 | "http://{}:{}/{}".format(Var.FQDN,
182 | Var.PORT,
183 | get_msg.message_id)
184 |
185 | msg_text ="""
186 | 𝗬𝗼𝘂𝗿 𝗟𝗶𝗻𝗸 𝗚𝗲𝗻𝗲𝗿𝗮𝘁𝗲𝗱 !\n
187 | 📂 Fɪʟᴇ ɴᴀᴍᴇ : {}\n
188 | 📦 Fɪʟᴇ ꜱɪᴢᴇ : {}\n
189 | 📥 Dᴏᴡɴʟᴏᴀᴅ : {}\n
190 | 🚸 Nᴏᴛᴇ : Lɪɴᴋ ᴇxᴘɪʀᴇᴅ ɪɴ 24 ʜᴏᴜʀꜱ\n
191 | 🍃 Bᴏᴛ Mᴀɪɴᴛᴀɪɴᴇᴅ Bʏ : @i_am_albin_praveen
192 | """
193 |
194 | await m.reply_text(
195 | text=msg_text.format(file_name, file_size, stream_link),
196 | parse_mode="HTML",
197 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Dᴏᴡɴʟᴏᴀᴅ ɴᴏᴡ 📥", url=stream_link)]])
198 | )
199 |
200 |
201 | @StreamBot.on_message(filters.private & filters.command(["about"]))
202 | async def start(bot, update):
203 | await update.reply_text(
204 | text=ABOUT_TEXT.format(update.from_user.mention),
205 | disable_web_page_preview=True,
206 | reply_markup=ABOUT_BUTTONS
207 | )
208 |
209 |
210 | @StreamBot.on_message(filters.command('help') & filters.private & ~filters.edited)
211 | async def help_handler(bot, message):
212 | if not await db.is_user_exist(message.from_user.id):
213 | await db.add_user(message.from_user.id)
214 | await bot.send_message(
215 | Var.BIN_CHANNEL,
216 | f"**Nᴇᴡ Usᴇʀ Jᴏɪɴᴇᴅ **\n\n__Mʏ Nᴇᴡ Fʀɪᴇɴᴅ__ [{message.from_user.first_name}](tg://user?id={message.from_user.id}) __Started Your Bot !!__"
217 | )
218 | if Var.UPDATES_CHANNEL is not None:
219 | try:
220 | user = await bot.get_chat_member(Var.UPDATES_CHANNEL, message.chat.id)
221 | if user.status == "kicked":
222 | await bot.send_message(
223 | chat_id=message.chat.id,
224 | text="Sᴏʀʀʏ Sɪʀ, Yᴏᴜ ᴀʀᴇ Bᴀɴɴᴇᴅ ᴛᴏ ᴜsᴇ ᴍᴇ. Cᴏɴᴛᴀᴄᴛ ᴛʜᴇ Dᴇᴠᴇʟᴏᴘᴇʀ",
225 | parse_mode="HTML",
226 | disable_web_page_preview=True
227 | )
228 | return
229 | except UserNotParticipant:
230 | await bot.send_message(
231 | chat_id=message.chat.id,
232 | text="**Pʟᴇᴀsᴇ Jᴏɪɴ Mʏ Uᴘᴅᴀᴛᴇs Cʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴛʜɪs Bᴏᴛ!**\n\n__Dᴜᴇ ᴛᴏ Oᴠᴇʀʟᴏᴀᴅ, Oɴʟʏ Cʜᴀɴɴᴇʟ Sᴜʙsᴄʀɪʙᴇʀs ᴄᴀɴ ᴜsᴇ ᴛʜᴇ Bᴏᴛ!__",
233 | reply_markup=InlineKeyboardMarkup(
234 | [[
235 | InlineKeyboardButton("🤖 Jᴏɪɴ Uᴘᴅᴀᴛᴇs Cʜᴀɴɴᴇʟ", url=f"https://t.me/{Var.UPDATES_CHANNEL}")
236 | ]]
237 | ),
238 | parse_mode="markdown"
239 | )
240 | return
241 | except Exception:
242 | await bot.send_message(
243 | chat_id=message.chat.id,
244 | text="__Sᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ Wʀᴏɴɢ. Cᴏɴᴛᴀᴄᴛ ᴍᴇ__ [ALBIN PRAVEEN](https://t.me/i_am_albin_praveen).",
245 | parse_mode="markdown",
246 | disable_web_page_preview=True)
247 | return
248 | await message.reply_text(
249 | text=HELP_TEXT,
250 | parse_mode="HTML",
251 | disable_web_page_preview=True,
252 | reply_markup=HELP_BUTTONS
253 | )
254 |
--------------------------------------------------------------------------------