├── 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 | --------------------------------------------------------------------------------