├── .changelog ├── .gitattributes ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── WebStreamer ├── __init__.py ├── __main__.py ├── bot │ ├── __init__.py │ ├── clients.py │ └── plugins │ │ ├── admin.py │ │ ├── callback.py │ │ ├── start.py │ │ └── stream.py ├── server │ ├── __init__.py │ ├── exceptions.py │ └── stream_routes.py ├── template │ ├── dl.html │ └── req.html ├── utils │ ├── Translation.py │ ├── __init__.py │ ├── broadcast_helper.py │ ├── custom_dl.py │ ├── database.py │ ├── file_properties.py │ ├── human_readable.py │ ├── keepalive.py │ ├── render_template.py │ └── time_format.py └── vars.py └── requirements.txt /.changelog: -------------------------------------------------------------------------------- 1 | - Fixed Bot not working in Channel 2 | - Removed files related to Heroku 3 | - Switched to Rotating Logs 4 | 5 | Updated Changes Made in EverythingSuckz's repo 6 | - README: update VPS deployment commands 7 | - Fix stream seeking 8 | - Fix bugs in stream seeking 9 | - Fix last_part_cut 10 | - REFACTOR: token parser 11 | - chore: remove heroku stuffs 12 | - Fix for files without filename 13 | - Fixed download with weird file name 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # IPython 77 | profile_default/ 78 | ipython_config.py 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | .dmypy.json 111 | dmypy.json 112 | 113 | # Pyre type checker 114 | .pyre/ 115 | 116 | #session files 117 | *.session 118 | *.session-journal 119 | 120 | .env 121 | test.py 122 | test2.py 123 | 124 | streambot.log.* -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "VSCord.enabled": true, 3 | "cSpell.words": [ 4 | "DYNO" 5 | ] 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
3 |
4 |
5 |
6 |
7 | A Telegram bot to stream files to web
8 | Demo Bot (Not Available)»
9 |
10 | Report a Bug
11 | |
12 | Request Feature
13 |
48 |
49 |
50 |
51 |
53 | This bot will give you stream links for Telegram files without the need of waiting till the download completes 54 |
55 | 56 | ### Original Repository 57 | 58 | The main working part was taken from [Megatron](https://github.com/eyaadh/megadlbot_oss) and thanks to [eyaadh](https://github.com/eyaadh) for his awesome project. 59 | 60 | ## How to make your own 61 | 62 | 63 | 64 | ### Host it on VPS or Locally 65 | 66 | ```sh 67 | git clone https://github.com/DeekshithSH/FileStreamBot 68 | cd FileStreamBot 69 | python3 -m venv ./venv 70 | . ./venv/bin/activate 71 | pip3 install -r requirements.txt 72 | python3 -m WebStreamer 73 | ``` 74 | 75 | and to stop the whole bot, 76 | do CTRL+C 77 | 78 | - **If you wanna run this bot 24/7 on the VPS, follow these steps.** 79 | ```sh 80 | sudo apt install tmux -y 81 | tmux 82 | python3 -m WebStreamer 83 | ``` 84 | 85 | now you can close the VPS and the bot will run on it. 86 | 87 | ## Setting up things 88 | 89 | If you're on Heroku, just add these in the Environmental Variables 90 | or if you're Locally hosting, create a file named `.env` in the root directory and add all the variables there. 91 | An example of `.env` file: 92 | 93 | ```sh 94 | API_ID=452525 95 | API_HASH=esx576f8738x883f3sfzx83 96 | BOT_TOKEN=55838383:yourtbottokenhere 97 | BIN_CHANNEL=-100 98 | DATABASE_URL=mongodb://admin:pAswaRd@192.168.27.1 99 | FQDN=192.168.27.1 100 | HAS_SSL=False 101 | MULTI_TOKEN1=55838383:yourfirstmulticlientbottokenhere 102 | MULTI_TOKEN2=55838383:yoursecondmulticlientbottokenhere 103 | MULTI_TOKEN3=55838383:yourthirdmulticlientbottokenhere 104 | OWNER_ID=777000 105 | PORT=8080 106 | ``` 107 | 108 | ### Mandatory Vars 109 | 110 | `API_ID` : Goto [my.telegram.org](https://my.telegram.org) to obtain this. 111 | 112 | `API_HASH` : Goto [my.telegram.org](https://my.telegram.org) to obtain this. 113 | 114 | `BOT_TOKEN` : Get the bot token from [@BotFather](https://telegram.dog/BotFather) 115 | 116 | `BIN_CHANNEL` : Create a new channel (private/public), post something in your channel. Forward that post to [@missrose_bot](https://telegram.dog/MissRose_bot) and **reply** `/id`. Now copy paste the forwarded channel ID in this field. 117 | 118 | `OWNER_ID` : Your Telegram User ID, Send `/id` to [@missrose_bot](https://telegram.dog/MissRose_bot) to get Your Telegram User ID 119 | 120 | `DATABASE_URL` : 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 [Me Telegram](https://t.me/Avishkarpatil). 121 | 122 | ### For MultiClient 123 | 124 | `MULTI_TOKEN1`: Add your first bot token or session strings here. 125 | 126 | `MULTI_TOKEN2`: Add your second bot token or session strings here. 127 | 128 | you may also add as many as bots you want. (max limit is not tested yet) 129 | `MULTI_TOKEN3`, `MULTI_TOKEN4`, etc. 130 | 131 | 132 | 133 | ### Optional Vars 134 | 135 | `SLEEP_THRESHOLD` : Set a sleep threshold for flood wait exceptions happening globally in this telegram bot instance, below which any request that raises a flood wait will be automatically invoked again after sleeping for the required amount of time. Flood wait exceptions requiring higher waiting times will be raised. Defaults to 60 seconds. 136 | 137 | `WORKERS` : Number of maximum concurrent workers for handling incoming updates. Defaults to `3` 138 | 139 | `PORT` : The port that you want your webapp to be listened to. Defaults to `8080` 140 | 141 | `WEB_SERVER_BIND_ADDRESS` : Your server bind address. Defauls to `0.0.0.0` 142 | 143 | `NO_PORT` : (can be either `True` or `False`) If you don't want your port to be displayed. You should point your `PORT` to `80` (http) or `443` (https) for the links to work. Ignore this if you're on Heroku. 144 | 145 | `FQDN` : A Fully Qualified Domain Name if present. Defaults to `WEB_SERVER_BIND_ADDRESS` 146 | 147 | `HAS_SSL` : (can be either `True` or `False`) If you want the generated links in https format. 148 | 149 | `PING_INTERVAL` : The time in ms you want the servers to be pinged each time to avoid sleeping (Only for Heroku). Defaults to `1200` or 20 minutes. 150 | 151 | `UPDATES_CHANNEL` : Your Telegram Channel 152 | 153 | `FORCE_UPDATES_CHANNEL` : Set to True, so every user have to Join update channel to use the bot. 154 | 155 | `SESSION_NAME` : Name for the Database created on your MongoDB. Defaults to `F2LxBot` 156 | 157 | `BANNED_CHANNELS` : Put IDs of Banned Channels where bot will not work. You can add multiple IDs & separate with Space. 158 | 159 | `KEEP_ALIVE` : If you want to make the server ping itself every `PING_INTERVAL` seconds to avoid sleeping. Helpful in PaaS Free tiers. Defaults to `False` 160 | 161 | ## How to use the bot 162 | 163 | :warning: **Before using the bot, don't forget to add all the bots (multi-client ones too) to the `BIN_CHANNEL` as an admin** 164 | 165 | `/start` : To check if the bot is alive or not. 166 | 167 | To get an instant stream link, just forward any media to the bot and boom, its fast af. 168 | 169 | ## faQ 170 | 171 | - How long the links will remain valid or is there any expiration time for the links generated by the bot? 172 | > The links will will be valid as longs as your bot is alive and you haven't deleted the log channel. 173 | 174 | ## Contributing 175 | 176 | Feel free to contribute to this project if you have any further ideas 177 | 178 | ## Contact me 179 | 180 | [](https://xn--r1a.click/AWeirdText) 181 | [](https://xn--r1a.click/AWeirdString) 182 | 183 | You can contact either via my [Telegram Group](https://xn--r1a.click/AWeirdString) ~~or you can PM me on [@DeekshithSH](https://xn--r1a.click/DeekshithSH)~~ 184 | 185 | 186 | ## Credits 187 | 188 | - [Me](https://xn--r1a.click/DeekshithSH) 189 | - [EverythingSuckz](https://github.com/EverythingSuckz) for his [FileStreamBot](https://github.com/EverythingSuckz/FileStreamBot) 190 | - [Avishkar Patil](https://github.com/avipatilpro) for his [FileStreamBot](https://github.com/avipatilpro/FileStreamBot) 191 | - [eyaadh](https://github.com/eyaadh) for his awesome [Megatron Bot](https://github.com/eyaadh/megadlbot_oss). 192 | - [BlackStone](https://github.com/eyMarv) for adding multi-client support. 193 | - [Dan Tès](https://telegram.dog/haskell) for his [Pyrogram Library](https://github.com/pyrogram/pyrogram) 194 | - [TheHamkerCat](https://github.com/TheHamkerCat) for helping me with my common doubts. 195 | -------------------------------------------------------------------------------- /WebStreamer/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | 4 | import time 5 | from .vars import Var 6 | from WebStreamer.bot.clients import StreamBot 7 | 8 | __version__ = 2.21 9 | StartTime = time.time() 10 | -------------------------------------------------------------------------------- /WebStreamer/__main__.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | import sys 4 | import asyncio 5 | import logging 6 | import logging.handlers as handlers 7 | from .vars import Var 8 | from aiohttp import web 9 | from pyrogram import idle 10 | from WebStreamer import utils 11 | from WebStreamer import StreamBot 12 | from WebStreamer.server import web_server 13 | from WebStreamer.bot.clients import initialize_clients 14 | 15 | 16 | logging.basicConfig( 17 | level=logging.INFO, 18 | datefmt="%d/%m/%Y %H:%M:%S", 19 | format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', 20 | handlers=[logging.StreamHandler(stream=sys.stdout), 21 | handlers.RotatingFileHandler("streambot.log", mode="a", maxBytes=104857600, backupCount=2, encoding="utf-8")],) 22 | 23 | logging.getLogger("aiohttp").setLevel(logging.ERROR) 24 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 25 | logging.getLogger("aiohttp.web").setLevel(logging.ERROR) 26 | 27 | server = web.AppRunner(web_server()) 28 | 29 | #if sys.version_info[1] > 9: 30 | # loop = asyncio.new_event_loop() 31 | # asyncio.set_event_loop(loop) 32 | #else: 33 | loop = asyncio.get_event_loop() 34 | 35 | async def start_services(): 36 | print() 37 | print("-------------------- Initializing Telegram Bot --------------------") 38 | await StreamBot.start() 39 | bot_info = await StreamBot.get_me() 40 | StreamBot.username = bot_info.username 41 | print("------------------------------ DONE ------------------------------") 42 | print() 43 | print( 44 | "---------------------- Initializing Clients ----------------------" 45 | ) 46 | await initialize_clients() 47 | print("------------------------------ DONE ------------------------------") 48 | if Var.KEEP_ALIVE: 49 | print("------------------ Starting Keep Alive Service ------------------") 50 | print() 51 | asyncio.create_task(utils.ping_server()) 52 | print("--------------------- Initializing Web Server ---------------------") 53 | await server.setup() 54 | await web.TCPSite(server, Var.BIND_ADDRESS, Var.PORT).start() 55 | print("------------------------------ DONE ------------------------------") 56 | print() 57 | print("------------------------- Service Started -------------------------") 58 | print(" bot =>> {}".format(bot_info.first_name)) 59 | if bot_info.dc_id: 60 | print(" DC ID =>> {}".format(str(bot_info.dc_id))) 61 | print(" URL =>> {}".format(Var.URL)) 62 | print("------------------------------------------------------------------") 63 | await idle() 64 | 65 | async def cleanup(): 66 | await server.cleanup() 67 | await StreamBot.stop() 68 | 69 | if __name__ == "__main__": 70 | try: 71 | loop.run_until_complete(start_services()) 72 | except KeyboardInterrupt: 73 | pass 74 | except Exception as err: 75 | logging.error(err.with_traceback(None)) 76 | finally: 77 | loop.run_until_complete(cleanup()) 78 | loop.stop() 79 | print("------------------------ Stopped Services ------------------------") -------------------------------------------------------------------------------- /WebStreamer/bot/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | 4 | from ..vars import Var 5 | from pyrogram import Client 6 | from os import getcwd 7 | 8 | StreamBot = Client( 9 | name="WebStreamer", 10 | api_id=Var.API_ID, 11 | api_hash=Var.API_HASH, 12 | workdir="WebStreamer", 13 | plugins={"root": "WebStreamer/bot/plugins"}, 14 | bot_token=Var.BOT_TOKEN, 15 | sleep_threshold=Var.SLEEP_THRESHOLD, 16 | workers=Var.WORKERS, 17 | ) 18 | 19 | multi_clients = {} 20 | work_loads = {} 21 | -------------------------------------------------------------------------------- /WebStreamer/bot/clients.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | import asyncio 4 | import logging 5 | from os import environ 6 | from ..vars import Var 7 | from pyrogram import Client 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 = dict( 15 | (c + 1, t) 16 | for c, (_, t) in enumerate( 17 | filter( 18 | lambda n: n[0].startswith("MULTI_TOKEN"), sorted(environ.items()) 19 | ) 20 | ) 21 | ) 22 | if not all_tokens: 23 | print("No additional clients found, using default client") 24 | return 25 | 26 | async def start_client(client_id, token): 27 | try: 28 | if len(token) >= 100: 29 | session_string=token 30 | bot_token=None 31 | print(f'Starting Client - {client_id} Using Session String') 32 | else: 33 | session_string=None 34 | bot_token=token 35 | print(f'Starting Client - {client_id} Using Bot Token') 36 | if client_id == len(all_tokens): 37 | await asyncio.sleep(2) 38 | print("This will take some time, please wait...") 39 | client = await Client( 40 | name=str(client_id), 41 | api_id=Var.API_ID, 42 | api_hash=Var.API_HASH, 43 | bot_token=bot_token, 44 | sleep_threshold=Var.SLEEP_THRESHOLD, 45 | no_updates=True, 46 | session_string=session_string, 47 | in_memory=True, 48 | ).start() 49 | work_loads[client_id] = 0 50 | return client_id, client 51 | except Exception: 52 | logging.error(f"Failed starting Client - {client_id} Error:", exc_info=True) 53 | 54 | clients = await asyncio.gather(*[start_client(i, token) for i, token in all_tokens.items()]) 55 | multi_clients.update(dict(clients)) 56 | if len(multi_clients) != 1: 57 | Var.MULTI_CLIENT = True 58 | print("Multi-Client Mode Enabled") 59 | else: 60 | print("No additional clients were initialized, using default client") 61 | -------------------------------------------------------------------------------- /WebStreamer/bot/plugins/admin.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | import os 4 | import time 5 | import string 6 | import random 7 | import asyncio 8 | import aiofiles 9 | import datetime 10 | from WebStreamer.utils.broadcast_helper import send_msg 11 | from WebStreamer.utils.database import Database 12 | from WebStreamer.bot import StreamBot 13 | from WebStreamer.vars import Var 14 | from pyrogram import filters, Client 15 | from pyrogram.types import Message 16 | from pyrogram.enums.parse_mode import ParseMode 17 | db = Database(Var.DATABASE_URL, Var.SESSION_NAME) 18 | broadcast_ids = {} 19 | 20 | 21 | @StreamBot.on_message(filters.command("status") & filters.private & filters.user(Var.OWNER_ID)) 22 | async def sts(c: Client, m: Message): 23 | total_users = await db.total_users_count() 24 | banned_users = await db.total_banned_users_count() 25 | await m.reply_text(text=f"**Total Users in DB:** `{total_users}` \n**Banned Users in DB:** `{banned_users}`", parse_mode=ParseMode.MARKDOWN, quote=True) 26 | 27 | @StreamBot.on_message(filters.command("ban") & filters.private & filters.user(Var.OWNER_ID)) 28 | async def sts(b, m: Message): 29 | id = m.text.split("/ban ")[-1] 30 | if not await db.is_user_banned(int(id)): 31 | await db.ban_user(int(id)) 32 | await db.delete_user(int(id)) 33 | if await db.is_user_banned(int(id)): 34 | await m.reply_text(text=f"`{id}`** is Banned** ", parse_mode=ParseMode.MARKDOWN, quote=True) 35 | await b.send_message( 36 | chat_id=id, 37 | text="**Your Banned to Use The Bot**", 38 | parse_mode=ParseMode.MARKDOWN, 39 | disable_web_page_preview=True 40 | ) 41 | else: 42 | await m.reply_text(text=f"**can't ban **`{id}`** something went wrong** ", parse_mode=ParseMode.MARKDOWN, quote=True) 43 | else: 44 | await m.reply_text(text=f"`{id}`** is Already Banned** ", parse_mode=ParseMode.MARKDOWN, quote=True) 45 | 46 | @StreamBot.on_message(filters.command("unban") & filters.private & filters.user(Var.OWNER_ID)) 47 | async def sts(b, m: Message): 48 | 49 | id = m.text.split("/unban ")[-1] 50 | if await db.is_user_banned(int(id)): 51 | await db.unban_user(int(id)) 52 | if not await db.is_user_banned(int(id)): 53 | await m.reply_text(text=f"`{id}`** is Unbanned** ", parse_mode=ParseMode.MARKDOWN, quote=True) 54 | await b.send_message( 55 | chat_id=id, 56 | text="**Your Unbanned now Use can use The Bot**", 57 | parse_mode=ParseMode.MARKDOWN, 58 | disable_web_page_preview=True 59 | ) 60 | else: 61 | await m.reply_text(text=f"**can't unban **`{id}`** something went wrong** ", parse_mode=ParseMode.MARKDOWN, quote=True) 62 | else: 63 | await m.reply_text(text=f"`{id}`** is not Banned** ", parse_mode=ParseMode.MARKDOWN, quote=True) 64 | 65 | @StreamBot.on_message(filters.command("broadcast") & filters.private & filters.user(Var.OWNER_ID) & filters.reply) 66 | async def broadcast_(c, m): 67 | all_users = await db.get_all_users() 68 | broadcast_msg = m.reply_to_message 69 | while True: 70 | broadcast_id = ''.join([random.choice(string.ascii_letters) for i in range(3)]) 71 | if not broadcast_ids.get(broadcast_id): 72 | break 73 | out = await m.reply_text( 74 | text=f"Broadcast initiated! You will be notified with log file when all the users are notified." 75 | ) 76 | start_time = time.time() 77 | total_users = await db.total_users_count() 78 | done = 0 79 | failed = 0 80 | success = 0 81 | broadcast_ids[broadcast_id] = dict( 82 | total=total_users, 83 | current=done, 84 | failed=failed, 85 | success=success 86 | ) 87 | async with aiofiles.open('broadcast.txt', 'w') as broadcast_log_file: 88 | async for user in all_users: 89 | sts, msg = await send_msg( 90 | user_id=int(user['id']), 91 | message=broadcast_msg 92 | ) 93 | if msg is not None: 94 | await broadcast_log_file.write(msg) 95 | if sts == 200: 96 | success += 1 97 | else: 98 | failed += 1 99 | if sts == 400: 100 | await db.delete_user(user['id']) 101 | done += 1 102 | if broadcast_ids.get(broadcast_id) is None: 103 | break 104 | else: 105 | broadcast_ids[broadcast_id].update( 106 | dict( 107 | current=done, 108 | failed=failed, 109 | success=success 110 | ) 111 | ) 112 | if broadcast_ids.get(broadcast_id): 113 | broadcast_ids.pop(broadcast_id) 114 | completed_in = datetime.timedelta(seconds=int(time.time() - start_time)) 115 | await asyncio.sleep(3) 116 | await out.delete() 117 | if failed == 0: 118 | await m.reply_text( 119 | text=f"broadcast completed in `{completed_in}`\n\nTotal users {total_users}.\nTotal done {done}, {success} success and {failed} failed.", 120 | quote=True 121 | ) 122 | else: 123 | await m.reply_document( 124 | document='broadcast.txt', 125 | caption=f"broadcast completed in `{completed_in}`\n\nTotal users {total_users}.\nTotal done {done}, {success} success and {failed} failed.", 126 | quote=True 127 | ) 128 | os.remove('broadcast.txt') 129 | -------------------------------------------------------------------------------- /WebStreamer/bot/plugins/callback.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | import random 4 | from WebStreamer.bot import StreamBot 5 | from WebStreamer.utils.file_properties import gen_link, get_media_file_unique_id 6 | from WebStreamer.vars import Var 7 | from WebStreamer.utils.Translation import Language, BUTTON 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 9 | from pyrogram.errors import MessageDeleteForbidden 10 | from pyrogram.enums.parse_mode import ParseMode 11 | 12 | 13 | deldbtnmsg=["Your Already Deleted the Link", "You can't undo the Action", "You can Resend the File to Regenerate New Link", "Why Clicking me Your Link is Dead", "This is Just a Button Showing that Your Link is Deleted"] 14 | 15 | @StreamBot.on_callback_query() 16 | async def cb_data(bot, update: CallbackQuery): 17 | lang = Language(update) 18 | if update.data == "home": 19 | await update.message.edit_text( 20 | text=lang.START_TEXT.format(update.from_user.mention), 21 | disable_web_page_preview=True, 22 | reply_markup=BUTTON.START_BUTTONS 23 | ) 24 | elif update.data == "help": 25 | await update.message.edit_text( 26 | text=lang.HELP_TEXT.format(Var.UPDATES_CHANNEL), 27 | disable_web_page_preview=True, 28 | reply_markup=BUTTON.HELP_BUTTONS 29 | ) 30 | elif update.data == "about": 31 | await update.message.edit_text( 32 | text=lang.ABOUT_TEXT, 33 | disable_web_page_preview=True, 34 | reply_markup=BUTTON.ABOUT_BUTTONS 35 | ) 36 | elif update.data == "close": 37 | await update.message.delete() 38 | elif update.data == "msgdeleted": 39 | await update.answer(random.choice(deldbtnmsg), show_alert=True) 40 | else: 41 | usr_cmd = update.data.split("_") 42 | if usr_cmd[0] == "msgdelconf2": 43 | await update.message.edit_text( 44 | text=update.message.text, 45 | disable_web_page_preview=True, 46 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("✔️", callback_data=f"msgdelyes_{usr_cmd[1]}_{usr_cmd[2]}"), InlineKeyboardButton("✖️", callback_data=f"msgdelno_{usr_cmd[1]}_{usr_cmd[2]}")]]) 47 | ) 48 | elif usr_cmd[0] == "msgdelno": 49 | get_msg = await bot.get_messages(chat_id=Var.BIN_CHANNEL, message_ids=int(usr_cmd[1])) 50 | if get_media_file_unique_id(get_msg) == usr_cmd[2]: 51 | reply_markup, Stream_Text, stream_link = await gen_link(m=update, log_msg=get_msg, from_channel=False) 52 | 53 | await update.message.edit_text( 54 | text=Stream_Text, 55 | disable_web_page_preview=True, 56 | reply_markup=reply_markup 57 | ) 58 | elif resp.empty: 59 | await update.answer("Sorry Your File is Missing from the Server", show_alert=True) 60 | else: 61 | await update.answer("Message id and file_unique_id miss match", show_alert=True) 62 | elif usr_cmd[0] == "msgdelyes": 63 | try: 64 | resp = await bot.get_messages(Var.BIN_CHANNEL, int(usr_cmd[1])) 65 | if get_media_file_unique_id(resp) == usr_cmd[2]: 66 | await bot.delete_messages( 67 | chat_id=Var.BIN_CHANNEL, 68 | message_ids=int(usr_cmd[1]) 69 | ) 70 | await update.message.edit_text( 71 | text=update.message.text, 72 | disable_web_page_preview=True, 73 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Link Deleted", callback_data="msgdeleted")]]) 74 | ) 75 | elif resp.empty: 76 | await update.answer("Sorry Your File is Missing from the Server", show_alert=True) 77 | else: 78 | await update.answer("Message id and file_unique_id miss match", show_alert=True) 79 | except MessageDeleteForbidden as e: 80 | print(e) 81 | await bot.send_message( 82 | chat_id=Var.BIN_CHANNEL, 83 | text=f"**#ᴇʀʀᴏʀ_ᴛʀᴀᴄᴇʙᴀᴄᴋ:** `{e}`\n#Delete_Link", disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN, 84 | ) 85 | await update.answer(text='message too old', show_alert=True) 86 | except Exception as e: 87 | print(e) 88 | error_id=await bot.send_message( 89 | chat_id=Var.BIN_CHANNEL, 90 | text=f"**#ᴇʀʀᴏʀ_ᴛʀᴀᴄᴇʙᴀᴄᴋ:** `{e}`\n#Delete_Link", disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN, 91 | ) 92 | await update.message.reply_text( 93 | text=f"**#ᴇʀʀᴏʀ_ᴛʀᴀᴄᴇʙᴀᴄᴋ:** `message-id={error_id.message_id}`\nYou can get Help from [Public Link Generator (Support)](https://t.me/{Var.UPDATES_CHANNEL})", disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN, 94 | ) 95 | else: 96 | await update.message.delete() -------------------------------------------------------------------------------- /WebStreamer/bot/plugins/start.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | from WebStreamer.bot import StreamBot 4 | from WebStreamer.vars import Var 5 | from WebStreamer.utils.database import Database 6 | from pyrogram import filters, Client 7 | from WebStreamer.utils.Translation import Language, BUTTON 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 9 | from pyrogram.errors import UserNotParticipant 10 | from pyrogram.enums.parse_mode import ParseMode 11 | 12 | db = Database(Var.DATABASE_URL, Var.SESSION_NAME) 13 | 14 | @StreamBot.on_message(filters.command('start') & filters.private) 15 | async def start(b, m): 16 | lang = Language(m) 17 | # Check The User is Banned or Not 18 | if await db.is_user_banned(m.from_user.id): 19 | await b.send_message( 20 | chat_id=m.chat.id, 21 | text=lang.ban_text.format(Var.OWNER_ID), 22 | parse_mode=ParseMode.MARKDOWN, 23 | disable_web_page_preview=True 24 | ) 25 | return 26 | if not await db.is_user_exist(m.from_user.id): 27 | await db.add_user(m.from_user.id) 28 | await b.send_message( 29 | Var.BIN_CHANNEL, 30 | f"**Nᴇᴡ Usᴇʀ Jᴏɪɴᴇᴅ:** \n\n__Mʏ Nᴇᴡ Fʀɪᴇɴᴅ__ [{m.from_user.first_name}](tg://user?id={m.from_user.id}) __Sᴛᴀʀᴛᴇᴅ Yᴏᴜʀ Bᴏᴛ !!__" 31 | ) 32 | usr_cmd = m.text.split("_")[-1] 33 | if Var.FORCE_UPDATES_CHANNEL: 34 | try: 35 | user = await b.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id) 36 | if user.status == "kicked": 37 | await b.send_message( 38 | chat_id=m.chat.id, 39 | text=lang.ban_text.format(Var.OWNER_ID), 40 | parse_mode=ParseMode.MARKDOWN, 41 | disable_web_page_preview=True 42 | ) 43 | return 44 | except UserNotParticipant: 45 | await b.send_message( 46 | chat_id=m.chat.id, 47 | text="Jᴏɪɴ ᴍʏ ᴜᴘᴅᴀᴛᴇ ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴍᴇ 🔐", 48 | reply_markup=InlineKeyboardMarkup( 49 | [[ 50 | InlineKeyboardButton("Jᴏɪɴ ɴᴏᴡ 🔓", url=f"https://t.me/{Var.UPDATES_CHANNEL}") 51 | ]] 52 | ), 53 | parse_mode=ParseMode.HTML 54 | ) 55 | return 56 | except Exception: 57 | await b.send_message( 58 | chat_id=m.chat.id, 59 | text=f"Sᴏᴍᴇᴛʜɪɴɢ ᴡʀᴏɴɢ ᴄᴏɴᴛᴀᴄᴛ ᴍʏ ᴅᴇᴠᴇʟᴏᴘᴇʀ [ ᴄʟɪᴄᴋ ʜᴇʀᴇ ]", 60 | parse_mode=ParseMode.HTML, 61 | disable_web_page_preview=True) 62 | return 63 | await m.reply_text( 64 | text=lang.START_TEXT.format(m.from_user.mention), 65 | parse_mode=ParseMode.HTML, 66 | disable_web_page_preview=True, 67 | reply_markup=BUTTON.START_BUTTONS 68 | ) 69 | 70 | 71 | @StreamBot.on_message(filters.private & filters.command(["about"])) 72 | async def start(bot, update): 73 | lang = Language(update) 74 | await update.reply_text( 75 | text=lang.ABOUT_TEXT.format(update.from_user.mention), 76 | disable_web_page_preview=True, 77 | reply_markup=BUTTON.ABOUT_BUTTONS 78 | ) 79 | 80 | 81 | @StreamBot.on_message((filters.command('help')) & filters.private) 82 | async def help_handler(bot, message): 83 | lang = Language(message) 84 | # Check The User is Banned or Not 85 | if await db.is_user_banned(message.from_user.id): 86 | await bot.send_message( 87 | chat_id=message.chat.id, 88 | text=lang.ban_text.format(Var.OWNER_ID), 89 | parse_mode=ParseMode.MARKDOWN, 90 | disable_web_page_preview=True 91 | ) 92 | return 93 | if not await db.is_user_exist(message.from_user.id): 94 | await db.add_user(message.from_user.id) 95 | await bot.send_message( 96 | Var.BIN_CHANNEL, 97 | f"**Nᴇᴡ Usᴇʀ Jᴏɪɴᴇᴅ **\n\n__Mʏ Nᴇᴡ Fʀɪᴇɴᴅ__ [{message.from_user.first_name}](tg://user?id={message.from_user.id}) __Started Your Bot !!__" 98 | ) 99 | if Var.FORCE_UPDATES_CHANNEL: 100 | try: 101 | user = await bot.get_chat_member(Var.UPDATES_CHANNEL, message.chat.id) 102 | if user.status == "kicked": 103 | await bot.send_message( 104 | chat_id=message.chat.id, 105 | text=lang.ban_text.format(Var.OWNER_ID), 106 | parse_mode=ParseMode.HTML, 107 | disable_web_page_preview=True 108 | ) 109 | return 110 | except UserNotParticipant: 111 | await bot.send_message( 112 | chat_id=message.chat.id, 113 | text="**Pʟᴇᴀsᴇ Jᴏɪɴ Mʏ Uᴘᴅᴀᴛᴇs Cʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴛʜɪs Bᴏᴛ!**\n\n__Dᴜᴇ ᴛᴏ Oᴠᴇʀʟᴏᴀᴅ, Oɴʟʏ Cʜᴀɴɴᴇʟ Sᴜʙsᴄʀɪʙᴇʀs ᴄᴀɴ ᴜsᴇ ᴛʜᴇ Bᴏᴛ!__", 114 | reply_markup=InlineKeyboardMarkup( 115 | [[ 116 | InlineKeyboardButton("🤖 Jᴏɪɴ Uᴘᴅᴀᴛᴇs Cʜᴀɴɴᴇʟ", url=f"https://t.me/{Var.UPDATES_CHANNEL}") 117 | ]] 118 | ), 119 | parse_mode=ParseMode.MARKDOWN 120 | ) 121 | return 122 | except Exception: 123 | await bot.send_message( 124 | chat_id=message.chat.id, 125 | text=f"__Sᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ Wʀᴏɴɢ. Cᴏɴᴛᴀᴄᴛ ᴍᴇ__ [ ᴄʟɪᴄᴋ ʜᴇʀᴇ ](https://t.me/{Var.UPDATES_CHANNEL}).", 126 | parse_mode=ParseMode.MARKDOWN, 127 | disable_web_page_preview=True) 128 | return 129 | await message.reply_text( 130 | text=lang.HELP_TEXT.format(Var.UPDATES_CHANNEL), 131 | parse_mode=ParseMode.HTML, 132 | disable_web_page_preview=True, 133 | reply_markup=BUTTON.HELP_BUTTONS 134 | ) 135 | 136 | # -----------------------------Only for me you can remove below line ------------------------------------------------------- 137 | 138 | @StreamBot.on_message(filters.command('getid') & filters.private) 139 | async def start(b, m): 140 | await b.send_message( 141 | chat_id=m.chat.id, 142 | text=f"Your ID is: `{m.chat.id}`" 143 | ) -------------------------------------------------------------------------------- /WebStreamer/bot/plugins/stream.py: -------------------------------------------------------------------------------- 1 | # This file is a part of FileStreamBot 2 | 3 | 4 | import asyncio 5 | from WebStreamer.utils.Translation import Language 6 | from WebStreamer.bot import StreamBot 7 | from WebStreamer.utils.database import Database 8 | from WebStreamer.utils.file_properties import gen_link, get_file_info, get_hash 9 | from WebStreamer.vars import Var 10 | from pyrogram import filters, Client 11 | from pyrogram.errors import FloodWait, UserNotParticipant 12 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton 13 | from pyrogram.enums.parse_mode import ParseMode 14 | db = Database(Var.DATABASE_URL, Var.SESSION_NAME) 15 | 16 | @StreamBot.on_message( 17 | filters.private 18 | & ( 19 | filters.document 20 | | filters.video 21 | | filters.audio 22 | | filters.animation 23 | | filters.voice 24 | | filters.video_note 25 | | filters.photo 26 | | filters.sticker 27 | ), 28 | group=4, 29 | ) 30 | async def private_receive_handler(c: Client, m: Message): 31 | lang = Language(m) 32 | # Check The User is Banned or Not 33 | if await db.is_user_banned(m.from_user.id): 34 | await c.send_message( 35 | chat_id=m.chat.id, 36 | text=lang.ban_text.format(Var.OWNER_ID), 37 | parse_mode=ParseMode.MARKDOWN, 38 | disable_web_page_preview=True 39 | ) 40 | return 41 | if not await db.is_user_exist(m.from_user.id): 42 | await db.add_user(m.from_user.id) 43 | await c.send_message( 44 | Var.BIN_CHANNEL, 45 | f"Nᴇᴡ Usᴇʀ Jᴏɪɴᴇᴅ : \n\nNᴀᴍᴇ : [{m.from_user.first_name}](tg://user?id={m.from_user.id}) Sᴛᴀʀᴛᴇᴅ Yᴏᴜʀ Bᴏᴛ !!" 46 | ) 47 | if Var.FORCE_UPDATES_CHANNEL: 48 | try: 49 | user = await c.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id) 50 | if user.status == "kicked": 51 | await c.send_message( 52 | chat_id=m.chat.id, 53 | text=lang.ban_text.format(Var.OWNER_ID), 54 | parse_mode=ParseMode.MARKDOWN, 55 | disable_web_page_preview=True 56 | ) 57 | return 58 | except UserNotParticipant: 59 | await c.send_message( 60 | chat_id=m.chat.id, 61 | text="""Jᴏɪɴ ᴍʏ ᴜᴘᴅᴀᴛᴇ ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜꜱᴇ ᴍᴇ 🔐""", 62 | reply_markup=InlineKeyboardMarkup( 63 | [[ InlineKeyboardButton("Jᴏɪɴ ɴᴏᴡ 🔓", url=f"https://t.me/{Var.UPDATES_CHANNEL}") ]] 64 | ), 65 | parse_mode=ParseMode.HTML 66 | ) 67 | return 68 | except Exception: 69 | await c.send_message( 70 | chat_id=m.chat.id, 71 | text=f"**Sᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ Wʀᴏɴɢ. [Cᴏɴᴛᴀᴄᴛ ᴍʏ ʙᴏss](tg://user?id={Var.OWNER_ID})**", 72 | parse_mode=ParseMode.MARKDOWN, 73 | disable_web_page_preview=True) 74 | return 75 | 76 | try: 77 | log_msg = await m.forward(chat_id=Var.BIN_CHANNEL) 78 | reply_markup, Stream_Text, stream_link = await gen_link(m=m, log_msg=log_msg, from_channel=False) 79 | 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=ParseMode.MARKDOWN, quote=True) 80 | # await db.add_file(get_file_info(log_msg,m)) 81 | await m.reply_text( 82 | text=Stream_Text, 83 | parse_mode=ParseMode.HTML, 84 | disable_web_page_preview=True, 85 | reply_markup=reply_markup, 86 | quote=True 87 | ) 88 | except FloodWait as e: 89 | print(f"Sleeping for {str(e.value)}s") 90 | await asyncio.sleep(e.value) 91 | await c.send_message(chat_id=Var.BIN_CHANNEL, text=f"Gᴏᴛ FʟᴏᴏᴅWᴀɪᴛ ᴏғ {str(e.value)}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=ParseMode.MARKDOWN) 92 | 93 | @StreamBot.on_message(filters.channel & (filters.document | filters.video), group=-1) 94 | async def channel_receive_handler(bot, broadcast: Message): 95 | if int(broadcast.chat.id) in Var.BANNED_CHANNELS: 96 | await bot.leave_chat(broadcast.chat.id) 97 | return 98 | try: 99 | log_msg = await broadcast.forward(chat_id=Var.BIN_CHANNEL) 100 | stream_link = "{}{}{}".format(Var.URL, get_hash(log_msg), log_msg.id) 101 | await log_msg.reply_text( 102 | text=f"**Cʜᴀɴɴᴇʟ Nᴀᴍᴇ:** `{broadcast.chat.title}`\n**Cʜᴀɴɴᴇʟ ID:** `{broadcast.chat.id}`\n**Rᴇǫᴜᴇsᴛ ᴜʀʟ:** https://t.me/{(await bot.get_me()).username}?start=msgid_{str(log_msg.id)}", 103 | # text=f"**Cʜᴀɴɴᴇʟ Nᴀᴍᴇ:** `{broadcast.chat.title}`\n**Cʜᴀɴɴᴇʟ ID:** `{broadcast.chat.id}`\n**Rᴇǫᴜᴇsᴛ ᴜʀʟ:** https://t.me/FxStreamBot?start=msgid_{str(log_msg.id)}", 104 | quote=True, 105 | parse_mode=ParseMode.MARKDOWN 106 | ) 107 | await bot.edit_message_reply_markup( 108 | chat_id=broadcast.chat.id, 109 | message_id=broadcast.id, 110 | reply_markup=InlineKeyboardMarkup( 111 | [[InlineKeyboardButton("Dᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ 📥", url=stream_link)]]) 112 | # [[InlineKeyboardButton("Dᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ 📥", url=f"https://t.me/{(await bot.get_me()).username}?start=msgid_{str(log_msg.id)}")]]) 113 | # [[InlineKeyboardButton("Dᴏᴡɴʟᴏᴀᴅ ʟɪɴᴋ 📥", url=f"https://t.me/FxStreamBot?start=msgid_{str(log_msg.id)}")]]) 114 | ) 115 | except FloodWait as w: 116 | print(f"Sleeping for {str(w.value)}s") 117 | await asyncio.sleep(w.value) 118 | await bot.send_message(chat_id=Var.BIN_CHANNEL, 119 | text=f"Gᴏᴛ FʟᴏᴏᴅWᴀɪᴛ ᴏғ {str(w.value)}s from {broadcast.chat.title}\n\n**Cʜᴀɴɴᴇʟ ID:** `{str(broadcast.chat.id)}`", 120 | disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN) 121 | except Exception as e: 122 | await bot.send_message(chat_id=Var.BIN_CHANNEL, text=f"**#ᴇʀʀᴏʀ_ᴛʀᴀᴄᴇʙᴀᴄᴋ:** `{e}`", disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN) 123 | print(f"Cᴀɴ'ᴛ Eᴅɪᴛ Bʀᴏᴀᴅᴄᴀsᴛ Mᴇssᴀɢᴇ!\nEʀʀᴏʀ: {e}") 124 | -------------------------------------------------------------------------------- /WebStreamer/server/__init__.py: -------------------------------------------------------------------------------- 1 | # Taken from megadlbot_oss