File name :
58 |59 |
{{file_name}}
60 |🩷 Thanks for Being Here 🩷
6 | 7 | 8 | 9 | ### 🥰 FEATURES 10 | 11 |➜ 𝖠𝖽𝖽 𝖳𝗈 𝖢𝗁𝖺𝗇𝗇𝖾𝗅""" 28 | 29 | @StreamBot.on_message(filters.command("start") & filters.private ) 30 | async def start(b, m): 31 | if not await db.is_user_exist(m.from_user.id): 32 | await db.add_user(m.from_user.id) 33 | await b.send_message( 34 | Var.NEW_USER_LOG, 35 | f"#𝐍𝐞𝐰𝐔𝐬𝐞𝐫\n\n**᚛› 𝐍𝐚𝐦𝐞 - [{m.from_user.first_name}](tg://user?id={m.from_user.id})**" 36 | ) 37 | if Var.UPDATES_CHANNEL != "None": 38 | try: 39 | user = await b.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id) 40 | if user.status == "kicked": 41 | await b.send_message( 42 | chat_id=m.chat.id, 43 | text="ꜱᴏʀʀʏ ʏᴏᴜ ᴀʀᴇ ʙᴀɴɴᴇᴅ ᴛᴏ ᴜꜱᴇ ᴍᴇ ᴘʟᴇᴀꜱᴇ ᴄᴏɴᴛᴀᴄᴛ ᴏᴡɴᴇʀ ꜰᴏʀ ᴍᴏʀᴇ ᴅᴇᴛᴀɪʟꜱ.", 44 | disable_web_page_preview=True 45 | ) 46 | return 47 | except UserNotParticipant: 48 | await StreamBot.send_photo( 49 | chat_id=m.chat.id, 50 | photo="https://graph.org/file/a8095ab3c9202607e78ad.jpg", 51 | caption=f"{m.from_user.mention},\n\n⚠️ ᴊᴏɪɴ ᴍʏ ᴜᴘᴅᴀᴛᴇs ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴍᴇ.\n\nᴅᴜᴇ ᴛᴏ sᴇʀᴠᴇʀ ᴏᴠᴇʀʟᴏᴀᴅ, ᴏɴʟʏ ᴏᴜʀ ᴄʜᴀɴɴᴇʟ sᴜʙsᴄʀɪʙᴇʀs ᴄᴀɴ ᴜsᴇ ᴛʜɪs ʙᴏᴛ 😊", 52 | reply_markup=InlineKeyboardMarkup( 53 | [ 54 | [ 55 | InlineKeyboardButton("ᴊᴏɪɴ ɴᴏᴡ 🚩", url=f"https://telegram.me/{Var.UPDATES_CHANNEL}") 56 | ] 57 | ] 58 | ), 59 | 60 | ) 61 | return 62 | except Exception: 63 | await b.send_message( 64 | chat_id=m.chat.id, 65 | text="ꜱᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ ᴡʀᴏɴɢ ᴄʟɪᴄᴋ ʜᴇʀᴇ ꜰᴏʀ ꜱᴜᴘᴘᴏʀᴛ", 66 | 67 | disable_web_page_preview=True) 68 | return 69 | await StreamBot.send_photo( 70 | chat_id=m.chat.id, 71 | photo=random.choice(Var.PICS), 72 | caption= TechifyBots.format(m.from_user.mention(style="md")), 73 | reply_markup=InlineKeyboardMarkup( 74 | [ 75 | [ 76 | InlineKeyboardButton("• ᴀʙᴏᴜᴛ •", callback_data="about"), 77 | InlineKeyboardButton("• ʜᴇʟᴘ •", callback_data="help") 78 | ], 79 | [ 80 | InlineKeyboardButton("♻ ᴅᴇᴠᴇʟᴏᴘᴇʀ ♻", url="https://telegram.me/TechifyRahul") 81 | ] 82 | ] 83 | ) 84 | ) 85 | 86 | @StreamBot.on_message(filters.command("help") & filters.private ) 87 | async def help_cd(b, m): 88 | if not await db.is_user_exist(m.from_user.id): 89 | await db.add_user(m.from_user.id) 90 | await b.send_message( 91 | Var.NEW_USER_LOG, 92 | f"#𝐍𝐞𝐰𝐔𝐬𝐞𝐫\n\n**᚛› 𝐍𝐚𝐦𝐞 - [{m.from_user.first_name}](tg://user?id={m.from_user.id})**" 93 | ) 94 | if Var.UPDATES_CHANNEL != "None": 95 | try: 96 | user = await b.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id) 97 | if user.status == "kicked": 98 | await b.send_message( 99 | chat_id=m.chat.id, 100 | text="ꜱᴏʀʀʏ ʏᴏᴜ ᴀʀᴇ ʙᴀɴɴᴇᴅ ᴛᴏ ᴜꜱᴇ ᴍᴇ ᴘʟᴇᴀꜱᴇ ᴄᴏɴᴛᴀᴄᴛ ᴏᴡɴᴇʀ ꜰᴏʀ ᴍᴏʀᴇ ᴅᴇᴛᴀɪʟꜱ.", 101 | disable_web_page_preview=True 102 | ) 103 | return 104 | except UserNotParticipant: 105 | await StreamBot.send_photo( 106 | chat_id=m.chat.id, 107 | photo="https://graph.org/file/a8095ab3c9202607e78ad.jpg", 108 | caption=f"{m.from_user.mention},\n\n⚠️ ᴊᴏɪɴ ᴍʏ ᴜᴘᴅᴀᴛᴇs ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴍᴇ.\n\nᴅᴜᴇ ᴛᴏ sᴇʀᴠᴇʀ ᴏᴠᴇʀʟᴏᴀᴅ, ᴏɴʟʏ ᴏᴜʀ ᴄʜᴀɴɴᴇʟ sᴜʙsᴄʀɪʙᴇʀs ᴄᴀɴ ᴜsᴇ ᴛʜɪs ʙᴏᴛ 😊", 109 | reply_markup=InlineKeyboardMarkup( 110 | [ 111 | [ 112 | InlineKeyboardButton("ᴊᴏɪɴ ɴᴏᴡ 🚩", url=f"https://telegram.me/{Var.UPDATES_CHANNEL}") 113 | ] 114 | ] 115 | ), 116 | 117 | ) 118 | return 119 | except Exception: 120 | await b.send_message( 121 | chat_id=m.chat.id, 122 | text="ꜱᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ ᴡʀᴏɴɢ ᴄᴏɴᴛᴀᴄᴛ [ᴏᴡɴᴇʀ](https://telegram.me/callOwnerBot).", 123 | disable_web_page_preview=True) 124 | return 125 | await StreamBot.send_photo( 126 | chat_id=m.chat.id, 127 | photo=random.choice(Var.PICS), 128 | caption="""You Don't Need Many Commands To Use This Bot 😅. 129 | 130 | Just Send Me Files And I Will Give You Direct Download & Streaming Link. 131 | 132 | Also You Can Use Me In Your Channel..Just Add Me And Make Me Admin And See My Power 🔥""", 133 | reply_markup=InlineKeyboardMarkup( 134 | [ 135 | [InlineKeyboardButton("👨💻 ʀᴇᴘᴏ", url="https://github.com/TechifyBots/File-Stream-Bot"), 136 | InlineKeyboardButton("💥 ᴅᴏɴᴀᴛᴇ", callback_data="donate")], 137 | [InlineKeyboardButton("✗ ᴄʟᴏsᴇ ✗", callback_data="close")] 138 | ] 139 | ) 140 | ) 141 | 142 | @StreamBot.on_message(filters.command('ban') & filters.user(Var.OWNER_ID)) 143 | async def do_ban(bot , message): 144 | userid = message.text.split(" ", 2)[1] if len(message.text.split(" ", 1)) > 1 else None 145 | reason = message.text.split(" ", 2)[2] if len(message.text.split(" ", 2)) > 2 else None 146 | if not userid: 147 | return await message.reply('ᴘʟᴇᴀsᴇ ᴀᴅᴅ ᴀ ᴠᴀʟɪᴅ ᴜsᴇʀ/ᴄʜᴀɴɴᴇʟ ɪᴅ ᴡɪᴛʜ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ\n\nᴇx : /ban (user/channel_id) (banning reason[Optional]) \nʀᴇᴀʟ ᴇx :
/ban 1234567899
\nᴡɪᴛʜ ʀᴇᴀsᴏɴ ᴇx:/ban 1234567899 seding adult links to bot
\nᴛᴏ ʙᴀɴ ᴀ ᴄʜᴀɴɴᴇʟ :\n/ban CHANEL_ID
\nᴇx : /ban -1001234567899
')
148 | text = await message.reply("ʟᴇᴛ ᴍᴇ ᴄʜᴇᴄᴋ 👀")
149 | banSts = await db.ban_user(userid)
150 | if banSts == True:
151 | await text.edit(
152 | text=f"{userid}
ʜᴀs ʙᴇᴇɴ ʙᴀɴɴᴇᴅ sᴜᴄᴄᴇssғᴜʟʟʏ\n\nSʜᴏᴜʟᴅ I sᴇɴᴅ ᴀɴ ᴀʟᴇʀᴛ ᴛᴏ ᴛʜᴇ ʙᴀɴɴᴇᴅ ᴜsᴇʀ?",
153 | reply_markup=InlineKeyboardMarkup(
154 | [
155 | [
156 | InlineKeyboardButton("ʏᴇs ✅", callback_data=f"sendAlert_{userid}_{reason if reason else 'no reason provided'}"),
157 | InlineKeyboardButton("ɴᴏ ❌", callback_data=f"noAlert_{userid}"),
158 | ],
159 | ]
160 | ),
161 | )
162 | else:
163 | await text.edit(f"Cᴏɴᴛʀᴏʟʟ ʏᴏᴜʀ ᴀɴɢᴇʀ ʙʀᴏ...\n{userid}
ɪs ᴀʟʀᴇᴀᴅʏ ʙᴀɴɴᴇᴅ !!")
164 | return
165 |
166 |
167 | @StreamBot.on_message(filters.command('unban') & filters.user(Var.OWNER_ID))
168 | async def do_unban(bot , message):
169 | userid = message.text.split(" ", 2)[1] if len(message.text.split(" ", 1)) > 1 else None
170 | if not userid:
171 | return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀɴ ɪᴅ\nᴇx : /unban 1234567899')
172 | text = await message.reply("ʟᴇᴛ ᴍᴇ ᴄʜᴇᴄᴋ 🥱")
173 | unban_chk = await db.is_unbanned(userid)
174 | if unban_chk == True:
175 | await text.edit(text=f'{userid}
ɪs ᴜɴʙᴀɴɴᴇᴅ\nSʜᴏᴜʟᴅ I sᴇɴᴅ ᴛʜᴇ ʜᴀᴘᴘʏ ɴᴇᴡs ᴀʟᴇʀᴛ ᴛᴏ ᴛʜᴇ ᴜɴʙᴀɴɴᴇᴅ ᴜsᴇʀ?',
176 | reply_markup=InlineKeyboardMarkup(
177 | [
178 | [
179 | InlineKeyboardButton("ʏᴇs ✅", callback_data=f"sendUnbanAlert_{userid}"),
180 | InlineKeyboardButton("ɴᴏ ❌", callback_data=f"NoUnbanAlert_{userid}"),
181 | ],
182 | ]
183 | ),
184 | )
185 |
186 | elif unban_chk==False:
187 | await text.edit('ᴜsᴇʀ ɪs ɴᴏᴛ ʙᴀɴɴᴇᴅ ʏᴇᴛ.')
188 | else :
189 | await text.edit(f"ғᴀɪʟᴇᴅ ᴛᴏ ᴜɴʙᴀɴ ᴜsᴇʀ/ᴄʜᴀɴɴᴇʟ.\nʀᴇᴀsᴏɴ : {unban_chk}")
190 |
191 | @StreamBot.on_callback_query()
192 | async def cb_handler(client, query):
193 | data = query.data
194 | if data == "close":
195 | await query.message.delete()
196 |
197 |
198 | if data == "start":
199 | await query.message.edit_caption(
200 | caption= TechifyBots.format(query.from_user.mention(style="md")),
201 | reply_markup=InlineKeyboardMarkup(
202 | [
203 | [
204 | InlineKeyboardButton("• ᴀʙᴏᴜᴛ •", callback_data="about"),
205 | InlineKeyboardButton("• ʜᴇʟᴘ •", callback_data="help")
206 | ],
207 | [
208 | InlineKeyboardButton("♻ ᴅᴇᴠᴇʟᴏᴘᴇʀ ♻", url="https://telegram.me/TechifyRahul")
209 | ]
210 | ]
211 | )
212 | )
213 |
214 | elif data == "about":
215 | await query.message.edit_caption(
216 | caption=f"ᴍʏ ɴᴀᴍᴇ : ʟɪɴᴋ sᴛʀᴇᴀᴍ ʀᴏʙᴏᴛ\nʜᴏsᴛᴇᴅ ᴏɴ : ᴋᴏʏᴇʙ\nᴅᴀᴛᴀʙᴀsᴇ : ᴍᴏɴɢᴏ ᴅʙ\nʟᴀɴɢᴜᴀɢᴇ : ᴘʏᴛʜᴏɴ 𝟹\nᴍʏ ᴄʀᴇᴀᴛᴏʀ : ʀᴀʜᴜʟ",
217 | reply_markup=InlineKeyboardMarkup(
218 | [[
219 | InlineKeyboardButton("ʜᴏᴍᴇ", callback_data="start"),
220 | InlineKeyboardButton("ᴄʟᴏsᴇ", callback_data="close")
221 | ]]
222 | )
223 | )
224 | elif data == "donate":
225 | await query.message.edit_caption(
226 | caption=f"❤️🔥 𝐓𝐡𝐚𝐧𝐤𝐬 𝐟𝐨𝐫 𝐬𝐡𝐨𝐰𝐢𝐧𝐠 𝐢𝐧𝐭𝐞𝐫𝐞𝐬𝐭 𝐢𝐧 𝐃𝐨𝐧𝐚𝐭𝐢𝐨𝐧
\n\n💞 ɪꜰ ʏᴏᴜ ʟɪᴋᴇ ᴏᴜʀ ʙᴏᴛ ꜰᴇᴇʟ ꜰʀᴇᴇ ᴛᴏ ᴅᴏɴᴀᴛᴇ ᴀɴʏ ᴀᴍᴏᴜɴᴛ ₹𝟷𝟶, ₹𝟸𝟶, ₹𝟻𝟶, ₹𝟷𝟶𝟶, ᴇᴛᴄ.\n\n❣️ 𝐷𝑜𝑛𝑎𝑡𝑖𝑜𝑛𝑠 𝑎𝑟𝑒 𝑟𝑒𝑎𝑙𝑙𝑦 𝑎𝑝𝑝𝑟𝑒𝑐𝑖𝑎𝑡𝑒𝑑 𝑖𝑡 ℎ𝑒𝑙𝑝𝑠 𝑖𝑛 𝑏𝑜𝑡 𝑑𝑒𝑣𝑒𝑙𝑜𝑝𝑚𝑒𝑛𝑡\n\n💖 𝐔𝐏𝐈 𝐈𝐃 : TechifyBots@UPI
",
227 | reply_markup=InlineKeyboardMarkup(
228 | [[
229 | InlineKeyboardButton("ʙᴀᴄᴋ", callback_data="help"),
230 | InlineKeyboardButton("ᴄʟᴏsᴇ", callback_data="close")
231 | ]]
232 | )
233 | )
234 |
235 | elif data == "help":
236 | await query.message.edit_caption(
237 | caption=f"You Don't Need Many Commands To Use This Bot 😅.\n\nJust Send Me Files And I Will Give You Direct Download & Streaming Link.\n\nAlso You Can Use Me In Your Channel..Just Add Me And Make Me Admin And See My Power 🔥",
238 | reply_markup=InlineKeyboardMarkup(
239 | [
240 | [InlineKeyboardButton("👨💻 ʀᴇᴘᴏ", url="https://github.com/TechifyBots/File-Stream-Bot"),
241 | InlineKeyboardButton("💥 ᴅᴏɴᴀᴛᴇ", callback_data="donate")],
242 | [InlineKeyboardButton("ʜᴏᴍᴇ", callback_data="start")]
243 | ]
244 | )
245 | )
246 |
247 | elif data.startswith("sendAlert"):
248 | user_id =(data.split("_")[1])
249 | user_id = int(user_id.replace(' ' , ''))
250 | if len(str(user_id)) == 10:
251 | reason = str(data.split("_")[2])
252 | try:
253 | await client.send_message(user_id , f"ʏᴏᴜ ᴀʀᴇ ʙᴀɴɴᴇᴅ ʙʏ [ʀᴀʜᴜʟ](https://telegram.me/callownerbot)\nʀᴇᴀsᴏɴ : {reason}")
254 | await query.message.edit(f"Aʟᴇʀᴛ sᴇɴᴛ ᴛᴏ {user_id}
\nʀᴇᴀsᴏɴ : {reason}")
255 | except Exception as e:
256 | await query.message.edit(f"sʀʏ ɪ ɢᴏᴛ ᴛʜɪs ᴇʀʀᴏʀ : {e}")
257 | else:
258 | await query.message.edit(f"Tʜᴇ ᴘʀᴏᴄᴇss ᴡᴀs ɴᴏᴛ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ʙᴇᴄᴀᴜsᴇ ᴛʜᴇ ᴜsᴇʀ ɪᴅ ᴡᴀs ɴᴏᴛ ᴠᴀʟɪᴅ, ᴏʀ ᴘᴇʀʜᴀᴘs ɪᴛ ᴡᴀs ᴀ ᴄʜᴀɴɴᴇʟ ɪᴅ")
259 |
260 | elif data.startswith('noAlert'):
261 | user_id =(data.split("_")[1])
262 | user_id = int(user_id.replace(' ' , ''))
263 | await query.message.edit(f"Tʜᴇ ʙᴀɴ ᴏɴ {user_id}
ᴡᴀs ᴇxᴇᴄᴜᴛᴇᴅ sɪʟᴇɴᴛʟʏ.")
264 |
265 | elif data.startswith('sendUnbanAlert'):
266 | user_id =(data.split("_")[1])
267 | user_id = int(user_id.replace(' ' , ''))
268 | if len(str(user_id)) == 10:
269 | try:
270 | unban_text = "ʜᴜʀʀᴀʏ..ʏᴏᴜ ᴀʀᴇ ᴜɴʙᴀɴɴᴇᴅ ʙʏ [ʀᴀʜᴜʟ](https://telegram.me/callownerbot)"
271 | await client.send_message(user_id , unban_text)
272 | await query.message.edit(f"Uɴʙᴀɴɴᴇᴅ Aʟᴇʀᴛ sᴇɴᴛ ᴛᴏ {user_id}
\nᴀʟᴇʀᴛ ᴛᴇxᴛ : {unban_text}")
273 | except Exception as e:
274 | await query.message.edit(f"sʀʏ ɪ ɢᴏᴛ ᴛʜɪs ᴇʀʀᴏʀ : {e}")
275 | else:
276 | await query.message.edit(f"Tʜᴇ ᴘʀᴏᴄᴇss ᴡᴀs ɴᴏᴛ ᴄᴏᴍᴘʟᴇᴛᴇᴅ ʙᴇᴄᴀᴜsᴇ ᴛʜᴇ ᴜsᴇʀ ɪᴅ ᴡᴀs ɴᴏᴛ ᴠᴀʟɪᴅ, ᴏʀ ᴘᴇʀʜᴀᴘs ɪᴛ ᴡᴀs ᴀ ᴄʜᴀɴɴᴇʟ ɪᴅ")
277 | elif data.startswith('NoUnbanAlert'):
278 | user_id =(data.split("_")[1])
279 | user_id = int(user_id.replace(' ' , ''))
280 | await query.message.edit(f"Tʜᴇ ᴜɴʙᴀɴ ᴏɴ {user_id}
ᴡᴀs ᴇxᴇᴄᴜᴛᴇᴅ sɪʟᴇɴᴛʟʏ.")
--------------------------------------------------------------------------------
/biisal/bot/plugins/stream.py:
--------------------------------------------------------------------------------
1 | #(c) Adarsh-Goel
2 | #(c) @biisal
3 | #(c) TechifyBots
4 | import os
5 | import asyncio
6 | import requests
7 | import string
8 | import random
9 | from asyncio import TimeoutError
10 | from biisal.bot import StreamBot
11 | from biisal.utils.database import Database
12 | from biisal.utils.human_readable import humanbytes
13 | from biisal.vars import Var
14 | from urllib.parse import quote_plus
15 | from pyrogram import filters, Client
16 | from pyrogram.errors import FloodWait, UserNotParticipant
17 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
18 |
19 | from biisal.utils.file_properties import get_name, get_hash, get_media_file_size
20 | db = Database(Var.DATABASE_URL, Var.name)
21 |
22 | def generate_random_alphanumeric():
23 | """Generate a random 8-letter alphanumeric string."""
24 | characters = string.ascii_letters + string.digits
25 | random_chars = ''.join(random.choice(characters) for _ in range(8))
26 | return random_chars
27 |
28 | def get_shortlink(url):
29 | rget = requests.get(f"https://{Var.SHORTLINK_URL}/api?api={Var.SHORTLINK_API}&url={url}&alias={generate_random_alphanumeric()}")
30 | rjson = rget.json()
31 | if rjson["status"] == "success" or rget.status_code == 200:
32 | return rjson["shortenedUrl"]
33 | else:
34 | return url
35 |
36 | MY_PASS = os.environ.get("MY_PASS", None)
37 | pass_dict = {}
38 | pass_db = Database(Var.DATABASE_URL, "ag_passwords")
39 |
40 | msg_text ="""
41 | ʏᴏᴜʀ ʟɪɴᴋ ɪs ɢᴇɴᴇʀᴀᴛᴇᴅ...⚡
42 |
43 | 📧 ꜰɪʟᴇ ɴᴀᴍᴇ :- {}
44 |
45 | 📦 ꜰɪʟᴇ sɪᴢᴇ :- {}
46 |
47 | ⚠️ ᴛʜɪꜱ ʟɪɴᴋ ᴡɪʟʟ ᴇxᴘɪʀᴇ ᴀꜰᴛᴇʀ 𝟼 ʜᴏᴜʀꜱ
48 |
49 | ❇️ ʙʏ : @TechifyBots"""
50 |
51 | @StreamBot.on_message((filters.private) & (filters.document | filters.video | filters.audio | filters.photo) , group=4)
52 | async def private_receive_handler(c: Client, m: Message):
53 | if not await db.is_user_exist(m.from_user.id):
54 | await db.add_user(m.from_user.id)
55 | await c.send_message(
56 | Var.NEW_USER_LOG,
57 | f"#𝐍𝐞𝐰𝐔𝐬𝐞𝐫\n\n**᚛› 𝐍𝐚𝐦𝐞 - [{m.from_user.first_name}](tg://user?id={m.from_user.id})**"
58 | )
59 | if Var.UPDATES_CHANNEL != "None":
60 | try:
61 | user = await c.get_chat_member(Var.UPDATES_CHANNEL, m.chat.id)
62 | if user.status == "kicked":
63 | await c.send_message(
64 | chat_id=m.chat.id,
65 | text="You are banned!\n\n Contact Developer [Rahul](https://telegram.me/CallOwnerBot) he will help you.",
66 | disable_web_page_preview=True
67 | )
68 | return
69 | except UserNotParticipant:
70 | await c.send_photo(
71 | chat_id=m.chat.id,
72 | photo="https://graph.org/file/a8095ab3c9202607e78ad.jpg",
73 | caption="""ᴊᴏɪɴ ᴏᴜʀ ᴜᴘᴅᴀᴛᴇs ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜꜱᴇ ᴍᴇ""",
74 | reply_markup=InlineKeyboardMarkup(
75 | [
76 | [
77 | InlineKeyboardButton("ᴊᴏɪɴ ɴᴏᴡ 🚩", url=f"https://telegram.me/{Var.UPDATES_CHANNEL}")
78 | ]
79 | ]
80 | ),
81 | )
82 | return
83 | except Exception as e:
84 | await m.reply_text(e)
85 | await c.send_message(
86 | chat_id=m.chat.id,
87 | text="sᴏᴍᴇᴛʜɪɴɢ ᴡᴇɴᴛ ᴡʀᴏɴɢ. ᴄᴏɴᴛᴀᴄᴛ ᴍʏ [ʙᴏss](https://telegram.me/CallOwnerBot)",
88 | disable_web_page_preview=True
89 | )
90 | return
91 | ban_chk = await db.is_banned(int(m.from_user.id))
92 | if ban_chk == True:
93 | return await m.reply(Var.BAN_ALERT)
94 |
95 | try: # This is the outer try block
96 | log_msg = await m.copy(chat_id=Var.BIN_CHANNEL)
97 | stream_link = f"{Var.URL}watch/{str(log_msg.id)}/{quote_plus(get_name(log_msg))}?hash={get_hash(log_msg)}"
98 | online_link = f"{Var.URL}{str(log_msg.id)}/{quote_plus(get_name(log_msg))}?hash={get_hash(log_msg)}"
99 | try: # This is the inner try block
100 | if Var.SHORTLINK:
101 | stream = get_shortlink(stream_link)
102 | download = get_shortlink(online_link)
103 | else:
104 | stream = stream_link
105 | download = online_link
106 | except Exception as e:
107 | print(f"An error occurred: {e}")
108 |
109 | a = await log_msg.reply_text(
110 | text=f"ʀᴇǫᴜᴇꜱᴛᴇᴅ ʙʏ : [{m.from_user.first_name}](tg://user?id={m.from_user.id})\nUꜱᴇʀ ɪᴅ : {m.from_user.id}\nStream ʟɪɴᴋ : {stream_link}",
111 | disable_web_page_preview=True, quote=True
112 | )
113 | k = await m.reply_text(
114 | text=msg_text.format(get_name(log_msg), humanbytes(get_media_file_size(m))),
115 | quote=True,
116 | reply_markup=InlineKeyboardMarkup([
117 | [InlineKeyboardButton("• ꜱᴛʀᴇᴀᴍ •", url=stream),
118 | InlineKeyboardButton("• ᴅᴏᴡɴʟᴏᴀᴅ •", url=download)],
119 | [InlineKeyboardButton('🧿 ᴡᴀᴛᴄʜ ᴏɴ ᴛᴇʟᴇɢʀᴀᴍ 🖥', web_app=WebAppInfo(url=stream))]
120 | ])
121 | )
122 |
123 | await m.delete() # Delete the original message after processing
124 |
125 | # Wait for 6 hours (21600 seconds)
126 | await asyncio.sleep(21600) # Sleep for 6 hours
127 |
128 | # After 6 hours, delete `log_msg`, `a`, and `k`
129 | try:
130 | await log_msg.delete()
131 | await a.delete()
132 | await k.delete()
133 | except Exception as e:
134 | print(f"Error during deletion: {e}")
135 |
136 | except FloodWait as e:
137 | print(f"Sleeping for {str(e.x)}s")
138 | await asyncio.sleep(e.x)
139 | 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)
140 |
141 | @StreamBot.on_message(filters.channel & ~filters.group & (filters.document | filters.video | filters.photo) & ~filters.forwarded, group=-1)
142 | async def channel_receive_handler(bot, broadcast):
143 | if int(broadcast.chat.id) in Var.BAN_CHNL:
144 | print("chat trying to get straming link is found in BAN_CHNL,so im not going to give stram link")
145 | return
146 | ban_chk = await db.is_banned(int(broadcast.chat.id))
147 | if (int(broadcast.chat.id) in Var.BANNED_CHANNELS) or (ban_chk == True):
148 | await bot.leave_chat(broadcast.chat.id)
149 | return
150 | try: # This is the outer try block
151 | log_msg = await broadcast.forward(chat_id=Var.BIN_CHANNEL)
152 | stream_link = f"{Var.URL}watch/{str(log_msg.id)}/{quote_plus(get_name(log_msg))}?hash={get_hash(log_msg)}"
153 | online_link = f"{Var.URL}{str(log_msg.id)}/{quote_plus(get_name(log_msg))}?hash={get_hash(log_msg)}"
154 | try: # This is the inner try block
155 | if Var.SHORTLINK:
156 | stream = get_shortlink(stream_link)
157 | download = get_shortlink(online_link)
158 | else:
159 | stream = stream_link
160 | download = online_link
161 | except Exception as e:
162 | print(f"An error occurred: {e}")
163 |
164 | await log_msg.reply_text(
165 | text=f"**Channel Name:** `{broadcast.chat.title}`\n**CHANNEL ID:** `{broadcast.chat.id}`\n**Rᴇǫᴜᴇsᴛ ᴜʀʟ:** {stream_link}",
166 | quote=True
167 | )
168 | await bot.edit_message_reply_markup(
169 | chat_id=broadcast.chat.id,
170 | message_id=broadcast.id,
171 | reply_markup=InlineKeyboardMarkup([
172 | [InlineKeyboardButton("ꜱᴛʀᴇᴀᴍ 🔺", url=stream),
173 | InlineKeyboardButton("ᴅᴏᴡɴʟᴏᴀᴅ 🔻", url=download)]
174 | ])
175 | )
176 | except FloodWait as w:
177 | print(f"Sleeping for {str(w.x)}s")
178 | await asyncio.sleep(w.x)
179 | await bot.send_message(chat_id=Var.BIN_CHANNEL,
180 | text=f"GOT FLOODWAIT OF {str(w.x)}s FROM {broadcast.chat.title}\n\n**CHANNEL ID:** `{str(broadcast.chat.id)}`",
181 | disable_web_page_preview=True)
182 | except Exception as e:
183 | await bot.send_message(chat_id=Var.BIN_CHANNEL, text=f"**#ERROR_TRACKEBACK:** `{e}`", disable_web_page_preview=True)
184 | print(f"Cᴀɴ'ᴛ Eᴅɪᴛ Bʀᴏᴀᴅᴄᴀsᴛ Mᴇssᴀɢᴇ!\nEʀʀᴏʀ: **Give me edit permission in updates and bin Channel!{e}**")
185 |
--------------------------------------------------------------------------------
/biisal/server/__init__.py:
--------------------------------------------------------------------------------
1 | # © agrprojects
2 |
3 | from aiohttp import web
4 | from .stream_routes import routes
5 |
6 |
7 | async def web_server():
8 | web_app = web.Application(client_max_size=30000000)
9 | web_app.add_routes(routes)
10 | return web_app
11 |
--------------------------------------------------------------------------------
/biisal/server/exceptions.py:
--------------------------------------------------------------------------------
1 |
2 | class InvalidHash(Exception):
3 | message = "Invalid hash"
4 |
5 | class FIleNotFound(Exception):
6 | message = "File not found"
--------------------------------------------------------------------------------
/biisal/server/stream_routes.py:
--------------------------------------------------------------------------------
1 | # Taken from megadlbot_oss
2 | # Thanks to Eyaadh
3 | # Thanks to adarsh-goel
4 | # (c) @biisal
5 | # (c) TechifyBots
6 | import re
7 | import time
8 | import math
9 | import logging
10 | import secrets
11 | import mimetypes
12 | from aiohttp import web
13 | from aiohttp.http_exceptions import BadStatusLine
14 | from biisal.bot import multi_clients, work_loads, StreamBot
15 | from biisal.server.exceptions import FIleNotFound, InvalidHash
16 | from biisal import StartTime, __version__
17 | from ..utils.time_format import get_readable_time
18 | from ..utils.custom_dl import ByteStreamer
19 | from biisal.utils.render_template import render_page
20 | from biisal.vars import Var
21 |
22 |
23 | routes = web.RouteTableDef()
24 |
25 | @routes.get("/", allow_head=True)
26 | async def root_route_handler(_):
27 | return web.json_response(
28 | {
29 | "server_status": "running",
30 | "uptime": get_readable_time(time.time() - StartTime),
31 | "telegram_bot": "@" + StreamBot.username,
32 | "connected_bots": len(multi_clients),
33 | "loads": dict(
34 | ("bot" + str(c + 1), l)
35 | for c, (_, l) in enumerate(
36 | sorted(work_loads.items(), key=lambda x: x[1], reverse=True)
37 | )
38 | ),
39 | "version": __version__,
40 | }
41 | )
42 |
43 |
44 | @routes.get(r"/watch/{path:\S+}", allow_head=True)
45 | async def stream_handler(request: web.Request):
46 | try:
47 | path = request.match_info["path"]
48 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path)
49 | if match:
50 | secure_hash = match.group(1)
51 | id = int(match.group(2))
52 | else:
53 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1))
54 | secure_hash = request.rel_url.query.get("hash")
55 | return web.Response(text=await render_page(id, secure_hash), content_type='text/html')
56 | except InvalidHash as e:
57 | raise web.HTTPForbidden(text=e.message)
58 | except FIleNotFound as e:
59 | raise web.HTTPNotFound(text=e.message)
60 | except (AttributeError, BadStatusLine, ConnectionResetError):
61 | pass
62 | except Exception as e:
63 | logging.critical(e.with_traceback(None))
64 | raise web.HTTPInternalServerError(text=str(e))
65 |
66 | @routes.get(r"/{path:\S+}", allow_head=True)
67 | async def stream_handler(request: web.Request):
68 | try:
69 | path = request.match_info["path"]
70 | match = re.search(r"^([a-zA-Z0-9_-]{6})(\d+)$", path)
71 | if match:
72 | secure_hash = match.group(1)
73 | id = int(match.group(2))
74 | else:
75 | id = int(re.search(r"(\d+)(?:\/\S+)?", path).group(1))
76 | secure_hash = request.rel_url.query.get("hash")
77 | return await media_streamer(request, id, secure_hash)
78 | except InvalidHash as e:
79 | raise web.HTTPForbidden(text=e.message)
80 | except FIleNotFound as e:
81 | raise web.HTTPNotFound(text=e.message)
82 | except (AttributeError, BadStatusLine, ConnectionResetError):
83 | pass
84 | except Exception as e:
85 | logging.critical(e.with_traceback(None))
86 | raise web.HTTPInternalServerError(text=str(e))
87 |
88 | class_cache = {}
89 |
90 | async def media_streamer(request: web.Request, id: int, secure_hash: str):
91 | range_header = request.headers.get("Range", 0)
92 |
93 | index = min(work_loads, key=work_loads.get)
94 | faster_client = multi_clients[index]
95 |
96 | if Var.MULTI_CLIENT:
97 | logging.info(f"Client {index} is now serving {request.remote}")
98 |
99 | if faster_client in class_cache:
100 | tg_connect = class_cache[faster_client]
101 | logging.debug(f"Using cached ByteStreamer object for client {index}")
102 | else:
103 | logging.debug(f"Creating new ByteStreamer object for client {index}")
104 | tg_connect = ByteStreamer(faster_client)
105 | class_cache[faster_client] = tg_connect
106 | logging.debug("before calling get_file_properties")
107 | file_id = await tg_connect.get_file_properties(id)
108 | logging.debug("after calling get_file_properties")
109 |
110 | if file_id.unique_id[:6] != secure_hash:
111 | logging.debug(f"Invalid hash for message with ID {id}")
112 | raise InvalidHash
113 |
114 | file_size = file_id.file_size
115 |
116 | if range_header:
117 | from_bytes, until_bytes = range_header.replace("bytes=", "").split("-")
118 | from_bytes = int(from_bytes)
119 | until_bytes = int(until_bytes) if until_bytes else file_size - 1
120 | else:
121 | from_bytes = request.http_range.start or 0
122 | until_bytes = (request.http_range.stop or file_size) - 1
123 |
124 | if (until_bytes > file_size) or (from_bytes < 0) or (until_bytes < from_bytes):
125 | return web.Response(
126 | status=416,
127 | body="416: Range not satisfiable",
128 | headers={"Content-Range": f"bytes */{file_size}"},
129 | )
130 |
131 | chunk_size = 1024 * 1024
132 | until_bytes = min(until_bytes, file_size - 1)
133 |
134 | offset = from_bytes - (from_bytes % chunk_size)
135 | first_part_cut = from_bytes - offset
136 | last_part_cut = until_bytes % chunk_size + 1
137 |
138 | req_length = until_bytes - from_bytes + 1
139 | part_count = math.ceil(until_bytes / chunk_size) - math.floor(offset / chunk_size)
140 | body = tg_connect.yield_file(
141 | file_id, index, offset, first_part_cut, last_part_cut, part_count, chunk_size
142 | )
143 |
144 | mime_type = file_id.mime_type
145 | file_name = file_id.file_name
146 | disposition = "attachment"
147 |
148 | if mime_type:
149 | if not file_name:
150 | try:
151 | file_name = f"{secrets.token_hex(2)}.{mime_type.split('/')[1]}"
152 | except (IndexError, AttributeError):
153 | file_name = f"{secrets.token_hex(2)}.unknown"
154 | else:
155 | if file_name:
156 | mime_type = mimetypes.guess_type(file_id.file_name)
157 | else:
158 | mime_type = "application/octet-stream"
159 | file_name = f"{secrets.token_hex(2)}.unknown"
160 |
161 | return web.Response(
162 | status=206 if range_header else 200,
163 | body=body,
164 | headers={
165 | "Content-Type": f"{mime_type}",
166 | "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
167 | "Content-Length": str(req_length),
168 | "Content-Disposition": f'{disposition}; filename="{file_name}"',
169 | "Accept-Ranges": "bytes",
170 | },
171 | )
172 |
--------------------------------------------------------------------------------
/biisal/template/TechifyBots.txt:
--------------------------------------------------------------------------------
1 | # © TechifyBots
2 |
--------------------------------------------------------------------------------
/biisal/template/dl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | %s
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
34 |
35 |
36 |
37 |
45 |
46 |
47 |
48 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/biisal/template/req.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | TECHIFY BOTS | {{file_name}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
39 |
40 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
55 |
56 |
57 | File name :
58 |
59 | {{file_name}}
60 |
61 |
62 |
64 |
66 |
69 |
71 |
73 |
76 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | WELCOME TO OUR STREAMING PAGE
87 |
88 | We're
89 | thrilled to have you here.
90 | Get ready for an
91 | amazing experience
92 | filled with entertainment, fun, and surprises.
93 | Grab
94 | your snacks, sit back, and enjoy the show!
95 |
96 |
97 |
111 |
122 |
131 |
132 |
133 |
134 |
135 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
189 |
190 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
--------------------------------------------------------------------------------
/biisal/utils/Rahul.txt:
--------------------------------------------------------------------------------
1 | # © TechifyBots (Rahul)
2 |
--------------------------------------------------------------------------------
/biisal/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # (c) adarsh-goel (c) @biisal (c) TechifyBots
2 |
--------------------------------------------------------------------------------
/biisal/utils/broadcast_helper.py:
--------------------------------------------------------------------------------
1 | # (c) TechifyBots
2 | # (c) @biisal
3 | # (c) adarsh-goel
4 | import asyncio
5 | import traceback
6 | from pyrogram.errors import FloodWait, InputUserDeactivated, UserIsBlocked, PeerIdInvalid
7 |
8 |
9 | async def send_msg(user_id, message):
10 | try:
11 | await message.forward(chat_id=user_id)
12 | return 200, None
13 | except FloodWait as e:
14 | await asyncio.sleep(e.x)
15 | return send_msg(user_id, message)
16 | except InputUserDeactivated:
17 | return 400, f"{user_id} : deactivated\n"
18 | except UserIsBlocked:
19 | return 400, f"{user_id} : blocked the bot\n"
20 | except PeerIdInvalid:
21 | return 400, f"{user_id} : user id invalid\n"
22 | except Exception as e:
23 | return 500, f"{user_id} : {traceback.format_exc()}\n"
24 |
--------------------------------------------------------------------------------
/biisal/utils/config_parser.py:
--------------------------------------------------------------------------------
1 | from os import environ
2 | from typing import Dict, Optional
3 |
4 |
5 | class TokenParser:
6 | def __init__(self, config_file: Optional[str] = None):
7 | self.tokens = {}
8 | self.config_file = config_file
9 |
10 | def parse_from_env(self) -> Dict[int, str]:
11 | self.tokens = dict(
12 | (c + 1, t)
13 | for c, (_, t) in enumerate(
14 | filter(
15 | lambda n: n[0].startswith("MULTI_TOKEN"), sorted(environ.items())
16 | )
17 | )
18 | )
19 | return self.tokens
20 |
--------------------------------------------------------------------------------
/biisal/utils/custom_dl.py:
--------------------------------------------------------------------------------
1 | import math
2 | import asyncio
3 | import logging
4 | from biisal.vars import Var
5 | from typing import Dict, Union
6 | from biisal.bot import work_loads
7 | from pyrogram import Client, utils, raw
8 | from .file_properties import get_file_ids
9 | from pyrogram.session import Session, Auth
10 | from pyrogram.errors import AuthBytesInvalid
11 | from biisal.server.exceptions import FIleNotFound
12 | from pyrogram.file_id import FileId, FileType, ThumbnailSource
13 |
14 |
15 | class ByteStreamer:
16 | def __init__(self, client: Client):
17 | """A custom class that holds the cache of a specific client and class functions.
18 | attributes:
19 | client: the client that the cache is for.
20 | cached_file_ids: a dict of cached file IDs.
21 | cached_file_properties: a dict of cached file properties.
22 |
23 | functions:
24 | generate_file_properties: returns the properties for a media of a specific message contained in Tuple.
25 | generate_media_session: returns the media session for the DC that contains the media file.
26 | yield_file: yield a file from telegram servers for streaming.
27 |
28 | This is a modified version of the
29 | Thanks to Eyaadh
30 | """
31 | self.clean_timer = 30 * 60
32 | self.client: Client = client
33 | self.cached_file_ids: Dict[int, FileId] = {}
34 | asyncio.create_task(self.clean_cache())
35 |
36 | async def get_file_properties(self, id: int) -> FileId:
37 | """
38 | Returns the properties of a media of a specific message in a FIleId class.
39 | if the properties are cached, then it'll return the cached results.
40 | or it'll generate the properties from the Message ID and cache them.
41 | """
42 | if id not in self.cached_file_ids:
43 | await self.generate_file_properties(id)
44 | logging.debug(f"Cached file properties for message with ID {id}")
45 | return self.cached_file_ids[id]
46 |
47 | async def generate_file_properties(self, id: int) -> FileId:
48 | """
49 | Generates the properties of a media file on a specific message.
50 | returns ths properties in a FIleId class.
51 | """
52 | file_id = await get_file_ids(self.client, Var.BIN_CHANNEL, id)
53 | logging.debug(f"Generated file ID and Unique ID for message with ID {id}")
54 | if not file_id:
55 | logging.debug(f"Message with ID {id} not found")
56 | raise FIleNotFound
57 | self.cached_file_ids[id] = file_id
58 | logging.debug(f"Cached media message with ID {id}")
59 | return self.cached_file_ids[id]
60 |
61 | async def generate_media_session(self, client: Client, file_id: FileId) -> Session:
62 | """
63 | Generates the media session for the DC that contains the media file.
64 | This is required for getting the bytes from Telegram servers.
65 | """
66 |
67 | media_session = client.media_sessions.get(file_id.dc_id, None)
68 |
69 | if media_session is None:
70 | if file_id.dc_id != await client.storage.dc_id():
71 | media_session = Session(
72 | client,
73 | file_id.dc_id,
74 | await Auth(
75 | client, file_id.dc_id, await client.storage.test_mode()
76 | ).create(),
77 | await client.storage.test_mode(),
78 | is_media=True,
79 | )
80 | await media_session.start()
81 |
82 | for _ in range(6):
83 | exported_auth = await client.invoke(
84 | raw.functions.auth.ExportAuthorization(dc_id=file_id.dc_id)
85 | )
86 |
87 | try:
88 | await media_session.send(
89 | raw.functions.auth.ImportAuthorization(
90 | id=exported_auth.id, bytes=exported_auth.bytes
91 | )
92 | )
93 | break
94 | except AuthBytesInvalid:
95 | logging.debug(
96 | f"Invalid authorization bytes for DC {file_id.dc_id}"
97 | )
98 | continue
99 | else:
100 | await media_session.stop()
101 | raise AuthBytesInvalid
102 | else:
103 | media_session = Session(
104 | client,
105 | file_id.dc_id,
106 | await client.storage.auth_key(),
107 | await client.storage.test_mode(),
108 | is_media=True,
109 | )
110 | await media_session.start()
111 | logging.debug(f"Created media session for DC {file_id.dc_id}")
112 | client.media_sessions[file_id.dc_id] = media_session
113 | else:
114 | logging.debug(f"Using cached media session for DC {file_id.dc_id}")
115 | return media_session
116 |
117 |
118 | @staticmethod
119 | async def get_location(file_id: FileId) -> Union[raw.types.InputPhotoFileLocation,
120 | raw.types.InputDocumentFileLocation,
121 | raw.types.InputPeerPhotoFileLocation,]:
122 | """
123 | Returns the file location for the media file.
124 | """
125 | file_type = file_id.file_type
126 |
127 | if file_type == FileType.CHAT_PHOTO:
128 | if file_id.chat_id > 0:
129 | peer = raw.types.InputPeerUser(
130 | user_id=file_id.chat_id, access_hash=file_id.chat_access_hash
131 | )
132 | else:
133 | if file_id.chat_access_hash == 0:
134 | peer = raw.types.InputPeerChat(chat_id=-file_id.chat_id)
135 | else:
136 | peer = raw.types.InputPeerChannel(
137 | channel_id=utils.get_channel_id(file_id.chat_id),
138 | access_hash=file_id.chat_access_hash,
139 | )
140 |
141 | location = raw.types.InputPeerPhotoFileLocation(
142 | peer=peer,
143 | volume_id=file_id.volume_id,
144 | local_id=file_id.local_id,
145 | big=file_id.thumbnail_source == ThumbnailSource.CHAT_PHOTO_BIG,
146 | )
147 | elif file_type == FileType.PHOTO:
148 | location = raw.types.InputPhotoFileLocation(
149 | id=file_id.media_id,
150 | access_hash=file_id.access_hash,
151 | file_reference=file_id.file_reference,
152 | thumb_size=file_id.thumbnail_size,
153 | )
154 | else:
155 | location = raw.types.InputDocumentFileLocation(
156 | id=file_id.media_id,
157 | access_hash=file_id.access_hash,
158 | file_reference=file_id.file_reference,
159 | thumb_size=file_id.thumbnail_size,
160 | )
161 | return location
162 |
163 | async def yield_file(
164 | self,
165 | file_id: FileId,
166 | index: int,
167 | offset: int,
168 | first_part_cut: int,
169 | last_part_cut: int,
170 | part_count: int,
171 | chunk_size: int,
172 | ) -> Union[str, None]:
173 | """
174 | Custom generator that yields the bytes of the media file.
175 | Modded from
176 | Thanks to Eyaadh
177 | """
178 | client = self.client
179 | work_loads[index] += 1
180 | logging.debug(f"Starting to yielding file with client {index}.")
181 | media_session = await self.generate_media_session(client, file_id)
182 |
183 | current_part = 1
184 | location = await self.get_location(file_id)
185 |
186 | try:
187 | r = await media_session.send(
188 | raw.functions.upload.GetFile(
189 | location=location, offset=offset, limit=chunk_size
190 | ),
191 | )
192 | if isinstance(r, raw.types.upload.File):
193 | while True:
194 | chunk = r.bytes
195 | if not chunk:
196 | break
197 | elif part_count == 1:
198 | yield chunk[first_part_cut:last_part_cut]
199 | elif current_part == 1:
200 | yield chunk[first_part_cut:]
201 | elif current_part == part_count:
202 | yield chunk[:last_part_cut]
203 | else:
204 | yield chunk
205 |
206 | current_part += 1
207 | offset += chunk_size
208 |
209 | if current_part > part_count:
210 | break
211 |
212 | r = await media_session.send(
213 | raw.functions.upload.GetFile(
214 | location=location, offset=offset, limit=chunk_size
215 | ),
216 | )
217 | except (TimeoutError, AttributeError):
218 | pass
219 | finally:
220 | logging.debug("Finished yielding file with {current_part} parts.")
221 | work_loads[index] -= 1
222 |
223 |
224 | async def clean_cache(self) -> None:
225 | """
226 | function to clean the cache to reduce memory usage
227 | """
228 | while True:
229 | await asyncio.sleep(self.clean_timer)
230 | self.cached_file_ids.clear()
231 | logging.debug("Cleaned the cache")
--------------------------------------------------------------------------------
/biisal/utils/database.py:
--------------------------------------------------------------------------------
1 | # (c) TechifyBots
2 | # (c) @biisal
3 | #(c) Adarsh-Goel
4 | import datetime
5 | import motor.motor_asyncio
6 |
7 |
8 | class Database:
9 | def __init__(self, uri, database_name):
10 | self._client = motor.motor_asyncio.AsyncIOMotorClient(uri)
11 | self.db = self._client[database_name]
12 | self.col = self.db.users
13 | self.bannedList = self.db.bannedList
14 |
15 | def new_user(self, id):
16 | return dict(
17 | id=id,
18 | join_date=datetime.date.today().isoformat()
19 | )
20 |
21 | async def add_user(self, id):
22 | user = self.new_user(id)
23 | await self.col.insert_one(user)
24 |
25 | async def add_user_pass(self, id, ag_pass):
26 | await self.add_user(int(id))
27 | await self.col.update_one({'id': int(id)}, {'$set': {'ag_p': ag_pass}})
28 |
29 | async def get_user_pass(self, id):
30 | user_pass = await self.col.find_one({'id': int(id)})
31 | return user_pass.get("ag_p", None) if user_pass else None
32 |
33 | async def is_user_exist(self, id):
34 | user = await self.col.find_one({'id': int(id)})
35 | return True if user else False
36 |
37 | async def total_users_count(self):
38 | count = await self.col.count_documents({})
39 | return count
40 |
41 | async def get_all_users(self):
42 | all_users = self.col.find({})
43 | return all_users
44 |
45 | async def delete_user(self, user_id):
46 | await self.col.delete_many({'id': int(user_id)})
47 |
48 | async def ban_user(self , user_id):
49 | user = await self.bannedList.find_one({'banId' : int(user_id)})
50 | if user:
51 | return False
52 | else:
53 | await self.bannedList.insert_one({'banId' : int(user_id)})
54 | return True
55 |
56 | async def is_banned(self , user_id):
57 | user = await self.bannedList.find_one({'banId' : int(user_id)})
58 | return True if user else False
59 |
60 | async def is_unbanned(self , user_id):
61 | try :
62 | if await self.bannedList.find_one({'banId' : int(user_id)}):
63 | await self.bannedList.delete_one({'banId' : int(user_id)})
64 | return True
65 | else:
66 | return False
67 | except Exception as e:
68 | e = f'Fᴀɪʟᴇᴅ ᴛᴏ ᴜɴʙᴀɴ.Rᴇᴀsᴏɴ : {e}'
69 | print(e)
70 | return e
71 |
--------------------------------------------------------------------------------
/biisal/utils/file_properties.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client
2 | from typing import Any, Optional
3 | from pyrogram.types import Message
4 | from pyrogram.file_id import FileId
5 | from pyrogram.raw.types.messages import Messages
6 | from biisal.server.exceptions import FIleNotFound
7 |
8 |
9 | async def parse_file_id(message: "Message") -> Optional[FileId]:
10 | media = get_media_from_message(message)
11 | if media:
12 | return FileId.decode(media.file_id)
13 |
14 | async def parse_file_unique_id(message: "Messages") -> Optional[str]:
15 | media = get_media_from_message(message)
16 | if media:
17 | return media.file_unique_id
18 |
19 | async def get_file_ids(client: Client, chat_id: int, id: int) -> Optional[FileId]:
20 | message = await client.get_messages(chat_id, id)
21 | if message.empty:
22 | raise FIleNotFound
23 | media = get_media_from_message(message)
24 | file_unique_id = await parse_file_unique_id(message)
25 | file_id = await parse_file_id(message)
26 | setattr(file_id, "file_size", getattr(media, "file_size", 0))
27 | setattr(file_id, "mime_type", getattr(media, "mime_type", ""))
28 | setattr(file_id, "file_name", getattr(media, "file_name", ""))
29 | setattr(file_id, "unique_id", file_unique_id)
30 | return file_id
31 |
32 | def get_media_from_message(message: "Message") -> Any:
33 | media_types = (
34 | "audio",
35 | "document",
36 | "photo",
37 | "sticker",
38 | "animation",
39 | "video",
40 | "voice",
41 | "video_note",
42 | )
43 | for attr in media_types:
44 | media = getattr(message, attr, None)
45 | if media:
46 | return media
47 |
48 |
49 | def get_hash(media_msg: Message) -> str:
50 | media = get_media_from_message(media_msg)
51 | return getattr(media, "file_unique_id", "")[:6]
52 |
53 | def get_name(media_msg: Message) -> str:
54 | media = get_media_from_message(media_msg)
55 | return getattr(media, 'file_name', "")
56 |
57 | def get_media_file_size(m):
58 | media = get_media_from_message(m)
59 | return getattr(media, "file_size", 0)
60 |
--------------------------------------------------------------------------------
/biisal/utils/file_size.py:
--------------------------------------------------------------------------------
1 | # (c) TechifyBots
2 | # (c) @biisal
3 | # (c) adarsh-goel
4 | def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
5 | """ Returns a human readable string representation of bytes """
6 | return str(bytes) + units[0] if int(bytes) < 1024 else human_size(int(bytes)>>10, units[1:])
7 |
--------------------------------------------------------------------------------
/biisal/utils/human_readable.py:
--------------------------------------------------------------------------------
1 | # (c) TechifyBots
2 | # (c) @biisal
3 | # (c) adarsh-goel
4 |
5 |
6 | def humanbytes(size):
7 | # https://stackoverflow.com/a/49361727/4723940
8 | # 2**10 = 1024
9 | if not size:
10 | return ""
11 | power = 2**10
12 | n = 0
13 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'}
14 | while size > power:
15 | size /= power
16 | n += 1
17 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B'
18 |
--------------------------------------------------------------------------------
/biisal/utils/keepalive.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import logging
3 | import aiohttp
4 | import traceback
5 | from biisal.vars import Var
6 |
7 |
8 | async def ping_server():
9 | sleep_time = Var.PING_INTERVAL
10 | while True:
11 | await asyncio.sleep(sleep_time)
12 | try:
13 | async with aiohttp.ClientSession(
14 | timeout=aiohttp.ClientTimeout(total=10)
15 | ) as session:
16 | async with session.get(Var.URL) as resp:
17 | logging.info("Pinged server with response: {}".format(resp.status))
18 | except TimeoutError:
19 | logging.warning("Couldn't connect to the site URL..!")
20 | except Exception:
21 | traceback.print_exc()
22 |
--------------------------------------------------------------------------------
/biisal/utils/render_template.py:
--------------------------------------------------------------------------------
1 | from biisal.vars import Var
2 | from biisal.bot import StreamBot
3 | from biisal.utils.human_readable import humanbytes
4 | from biisal.utils.file_properties import get_file_ids
5 | from biisal.server.exceptions import InvalidHash
6 | import urllib.parse
7 | import aiofiles
8 | import logging
9 | import aiohttp
10 | import jinja2
11 |
12 | async def render_page(id, secure_hash, src=None):
13 | file = await StreamBot.get_messages(int(Var.BIN_CHANNEL), int(id))
14 | file_data = await get_file_ids(StreamBot, int(Var.BIN_CHANNEL), int(id))
15 | if file_data.unique_id[:6] != secure_hash:
16 | logging.debug(f"link hash: {secure_hash} - {file_data.unique_id[:6]}")
17 | logging.debug(f"Invalid hash for message with - ID {id}")
18 | raise InvalidHash
19 |
20 | src = urllib.parse.urljoin(
21 | Var.URL,
22 | f"{id}/{urllib.parse.quote_plus(file_data.file_name)}?hash={secure_hash}",
23 | )
24 |
25 | tag = file_data.mime_type.split("/")[0].strip()
26 | file_size = humanbytes(file_data.file_size)
27 | if tag in ["video", "audio"]:
28 | template_file = "biisal/template/req.html"
29 | else:
30 | template_file = "biisal/template/dl.html"
31 | async with aiohttp.ClientSession() as s:
32 | async with s.get(src) as u:
33 | file_size = humanbytes(int(u.headers.get("Content-Length")))
34 |
35 | with open(template_file) as f:
36 | template = jinja2.Template(f.read())
37 |
38 | file_name = file_data.file_name.replace("_", " ")
39 |
40 | return template.render(
41 | file_name=file_name,
42 | file_url=src,
43 | file_size=file_size,
44 | file_unique_id=file_data.unique_id,
45 | )
--------------------------------------------------------------------------------
/biisal/utils/time_format.py:
--------------------------------------------------------------------------------
1 | # (c) @biisal
2 | # (c) adarsh-goel
3 | # (c) TechifyBots
4 |
5 | def get_readable_time(seconds: int) -> str:
6 | count = 0
7 | readable_time = ""
8 | time_list = []
9 | time_suffix_list = ["s", "m", "h", " days"]
10 | while count < 4:
11 | count += 1
12 | if count < 3:
13 | remainder, result = divmod(seconds, 60)
14 | else:
15 | remainder, result = divmod(seconds, 24)
16 | if seconds == 0 and remainder == 0:
17 | break
18 | time_list.append(int(result))
19 | seconds = int(remainder)
20 | for x in range(len(time_list)):
21 | time_list[x] = str(time_list[x]) + time_suffix_list[x]
22 | if len(time_list) == 4:
23 | readable_time += time_list.pop() + ", "
24 | time_list.reverse()
25 | readable_time += ": ".join(time_list)
26 | return readable_time
27 |
--------------------------------------------------------------------------------
/biisal/vars.py:
--------------------------------------------------------------------------------
1 | # (c) adarsh-goel (c) biisal (c) TechifyBots
2 | import os
3 | from os import getenv, environ
4 | from dotenv import load_dotenv
5 |
6 | def is_enabled(value, default):
7 | if value.lower() in ["true", "yes", "1", "enable", "y"]:
8 | return True
9 | elif value.lower() in ["false", "no", "0", "disable", "n"]:
10 | return False
11 | else:
12 | return default
13 |
14 | load_dotenv()
15 |
16 | class Var(object):
17 | MULTI_CLIENT = False
18 | API_ID = int(getenv('API_ID', ''))
19 | API_HASH = str(getenv('API_HASH', ''))
20 | BOT_TOKEN = str(getenv('BOT_TOKEN' , ''))
21 | PICS = (environ.get('PICS', 'https://envs.sh/jUp.jpg')).split()
22 | name = str(getenv('name', 'linkstreamrobot'))
23 | SLEEP_THRESHOLD = int(getenv('SLEEP_THRESHOLD', '60'))
24 | WORKERS = int(getenv('WORKERS', '4'))
25 | BIN_CHANNEL = int(getenv('BIN_CHANNEL', ''))
26 | NEW_USER_LOG = int(getenv('NEW_USER_LOG', ''))
27 | PORT = int(getenv('PORT', '8080'))
28 | BIND_ADRESS = str(getenv('WEB_SERVER_BIND_ADDRESS', '0.0.0.0'))
29 | PING_INTERVAL = int(environ.get("PING_INTERVAL", "1200")) # 20 minutes
30 | OWNER_ID = [int(x) for x in os.environ.get("OWNER_ID", "").split()]
31 | NO_PORT = bool(getenv('NO_PORT', False))
32 | APP_NAME = None
33 | OWNER_USERNAME = str(getenv('OWNER_USERNAME', 'TechifyRahul'))
34 | if 'DYNO' in environ:
35 | ON_HEROKU = True
36 | APP_NAME = str(getenv('APP_NAME')) #dont need to fill anything here
37 |
38 | else:
39 | ON_HEROKU = False
40 | FQDN = str(getenv('FQDN', 'BIND_ADRESS:PORT')) if not ON_HEROKU or getenv('FQDN', '') else APP_NAME+'.herokuapp.com'
41 | HAS_SSL=bool(getenv('HAS_SSL',True))
42 | if HAS_SSL:
43 | URL = "https://{}/".format(FQDN)
44 | else:
45 | URL = "http://{}/".format(FQDN)
46 | DATABASE_URL = str(getenv('DATABASE_URL', ''))
47 | UPDATES_CHANNEL = str(getenv('UPDATES_CHANNEL', 'TechifyBots'))
48 | BANNED_CHANNELS = list(set(int(x) for x in str(getenv("BANNED_CHANNELS", "")).split()))
49 | BAN_CHNL = list(set(int(x) for x in str(getenv("BAN_CHNL", "")).split()))
50 | BAN_ALERT = str(getenv('BAN_ALERT' , 'ʏᴏᴜʀ ᴀʀᴇ ʙᴀɴɴᴇᴅ ᴛᴏ ᴜsᴇ ᴛʜɪs ʙᴏᴛ.ᴄᴏɴᴛᴀᴄᴛ @CallOwnerBot ᴛᴏ ʀᴇsᴏʟᴠᴇ ᴛʜᴇ ɪssᴜᴇ!!'))
51 | SHORTLINK = is_enabled('SHORTLINK', False)
52 | SHORTLINK_URL = getenv('SHORTLINK_URL', '')
53 | SHORTLINK_API = getenv('SHORTLINK_API', '')
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyrofork==2.3.48
2 | tgcrypto<=1.2.3
3 | aiohttp<=3.8.1
4 | python-dotenv<=0.20.0
5 | motor
6 | aiofiles
7 | dnspython
8 | apscheduler
9 | requests
10 | psutil
11 | colorama
12 | jinja2
13 | Flask<= 3.0.0
14 | gunicorn<= 21.2.0
15 |
--------------------------------------------------------------------------------
/run cmd.txt:
--------------------------------------------------------------------------------
1 | python -m biisal
2 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.10.15
2 |
--------------------------------------------------------------------------------
/utils_bot.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import threading
4 | import time
5 | from asyncio import TimeoutError
6 | from pyrogram import filters
7 |
8 | LOGGER = logging.getLogger(__name__)
9 | SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
10 |
11 | class setInterval:
12 | def __init__(self, interval, action):
13 | self.interval = interval
14 | self.action = action
15 | self.stopEvent = threading.Event()
16 | thread = threading.Thread(target=self.__setInterval)
17 | thread.start()
18 |
19 | def __setInterval(self):
20 | nextTime = time.time() + self.interval
21 | while not self.stopEvent.wait(nextTime - time.time()):
22 | nextTime += self.interval
23 | self.action()
24 |
25 | def cancel(self):
26 | self.stopEvent.set()
27 |
28 |
29 | def get_readable_file_size(size_in_bytes) -> str:
30 | if size_in_bytes is None:
31 | return '0B'
32 | index = 0
33 | while size_in_bytes >= 1024:
34 | size_in_bytes /= 1024
35 | index += 1
36 | try:
37 | return f'{round(size_in_bytes, 2)}{SIZE_UNITS[index]}'
38 | except IndexError:
39 | return 'File too large'
40 |
41 |
42 | def get_readable_time(seconds: int) -> str:
43 | result = ''
44 | (days, remainder) = divmod(seconds, 86400)
45 | days = int(days)
46 | if days != 0:
47 | result += f'{days}d'
48 | (hours, remainder) = divmod(remainder, 3600)
49 | hours = int(hours)
50 | if hours != 0:
51 | result += f'{hours}h'
52 | (minutes, seconds) = divmod(remainder, 60)
53 | minutes = int(minutes)
54 | if minutes != 0:
55 | result += f'{minutes}m'
56 | seconds = int(seconds)
57 | result += f'{seconds}s'
58 | return result
59 |
60 |
61 |
62 | def readable_time(seconds: int) -> str:
63 | result = ''
64 | (days, remainder) = divmod(seconds, 86400)
65 | days = int(days)
66 | if days != 0:
67 | result += f'{days}d'
68 | (hours, remainder) = divmod(remainder, 3600)
69 | hours = int(hours)
70 | if hours != 0:
71 | result += f'{hours}h'
72 | (minutes, seconds) = divmod(remainder, 60)
73 | minutes = int(minutes)
74 | if minutes != 0:
75 | result += f'{minutes}m'
76 | seconds = int(seconds)
77 | result += f'{seconds}s'
78 | return result
79 |
--------------------------------------------------------------------------------