├── Procfile
├── WebStreamer
├── utils
│ ├── __init__.py
│ ├── keepalive.py
│ ├── time_format.py
│ └── custom_dl.py
├── server
│ ├── __init__.py
│ └── stream_routes.py
├── __init__.py
├── bot
│ ├── __init__.py
│ └── plugins
│ │ ├── start.py
│ │ └── stream.py
├── vars.py
└── __main__.py
├── requirements.txt
├── app.json
└── README.md
/Procfile:
--------------------------------------------------------------------------------
1 | web: python -m WebStreamer
--------------------------------------------------------------------------------
/WebStreamer/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp
2 | apscheduler
3 | pyrogram
4 | python-dotenv
5 | tgcrypto
--------------------------------------------------------------------------------
/WebStreamer/server/__init__.py:
--------------------------------------------------------------------------------
1 |
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 |
--------------------------------------------------------------------------------
/WebStreamer/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | import time
5 | from WebStreamer.bot import StreamBot
6 |
7 | print('\n')
8 | print('------------------- loading Telegram Bot -------------------')
9 |
10 | StreamBot.start()
11 | bot_info = StreamBot.get_me()
12 | __version__ = 1.03
13 | StartTime = time.time()
14 |
15 |
16 |
--------------------------------------------------------------------------------
/WebStreamer/bot/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | from pyrogram import Client
4 | from ..vars import Var
5 |
6 | StreamBot = Client(
7 | session_name= 'Web Streamer',
8 | api_id=Var.API_ID,
9 | api_hash=Var.API_HASH,
10 | bot_token=Var.BOT_TOKEN,
11 | sleep_threshold=Var.SLEEP_THRESHOLD,
12 | workers=Var.WORKERS
13 | )
14 |
--------------------------------------------------------------------------------
/WebStreamer/bot/plugins/start.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | from pyrogram import filters, emoji
4 | from WebStreamer.bot import StreamBot
5 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
6 |
7 | @StreamBot.on_message(filters.command(['start', 'help']))
8 | async def start(_, m: Message):
9 | await m.reply(f'Hi {m.from_user.mention(style="md")}, Send me a file to get an instant stream link.',
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/WebStreamer/utils/keepalive.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import aiohttp
3 | from WebStreamer.vars import Var
4 |
5 | async def ping_server():
6 | try:
7 | async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
8 | async with session.get(Var.URL) as resp:
9 | logging.info("Pinged server with response: {}".format(resp.status))
10 | except TimeoutError:
11 | logging.warning("Couldn't connect to the site URL..!")
--------------------------------------------------------------------------------
/WebStreamer/utils/time_format.py:
--------------------------------------------------------------------------------
1 | def get_readable_time(seconds: int) -> str:
2 | count = 0
3 | readable_time = ""
4 | time_list = []
5 | time_suffix_list = ["s", "m", "h", " days"]
6 | while count < 4:
7 | count += 1
8 | if count < 3:
9 | remainder, result = divmod(seconds, 60)
10 | else:
11 | remainder, result = divmod(seconds, 24)
12 | if seconds == 0 and remainder == 0:
13 | break
14 | time_list.append(int(result))
15 | seconds = int(remainder)
16 | for x in range(len(time_list)):
17 | time_list[x] = str(time_list[x]) + time_suffix_list[x]
18 | if len(time_list) == 4:
19 | readable_time += time_list.pop() + ", "
20 | time_list.reverse()
21 | readable_time += ": ".join(time_list)
22 | return readable_time
--------------------------------------------------------------------------------
/WebStreamer/vars.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | from os import getenv, environ
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
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 | SLEEP_THRESHOLD = int(getenv('SLEEP_THRESHOLD', '60'))
13 | WORKERS = int(getenv('WORKERS', '3'))
14 | BIN_CHANNEL = int(getenv('BIN_CHANNEL', None))
15 | PORT = int(getenv('PORT', 8080))
16 | BIND_ADRESS = str(getenv('WEB_SERVER_BIND_ADDRESS', '0.0.0.0'))
17 | HAS_SSL = getenv('HAS_SSL', False)
18 | HAS_SSL = True if str(HAS_SSL).lower() == 'true' else False
19 | # OWNER_ID = int(getenv('OWNER_ID')) #TODO
20 | NO_PORT = getenv('NO_PORT', False)
21 | NO_PORT = True if str(NO_PORT).lower() == 'true' else False
22 | if 'DYNO' in environ:
23 | ON_HEROKU = True
24 | APP_NAME = str(getenv('APP_NAME'))
25 | else:
26 | ON_HEROKU = False
27 | FQDN = str(getenv('FQDN', BIND_ADRESS)) if not ON_HEROKU or getenv('FQDN') else APP_NAME+'.herokuapp.com'
28 | if ON_HEROKU:
29 | URL = f"https://{FQDN}/"
30 | else:
31 | URL = "http{}://{}{}/".format('s' if HAS_SSL else '', FQDN, '' if NO_PORT else ':'+ str(PORT))
32 |
--------------------------------------------------------------------------------
/WebStreamer/bot/plugins/stream.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | from pyrogram import filters
4 | from WebStreamer.vars import Var
5 | from urllib.parse import quote_plus
6 | from WebStreamer.bot import StreamBot
7 | from pyrogram.types.messages_and_media import message
8 | from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
9 |
10 | def detect_type(m: Message):
11 | if m.document:
12 | return m.document
13 | elif m.video:
14 | return m.video
15 | elif m.audio:
16 | return m.audio
17 | else:
18 | return
19 |
20 |
21 | @StreamBot.on_message(filters.private & (filters.document | filters.video | filters.audio), group=4)
22 | async def media_receive_handler(_, m: Message):
23 | file = detect_type(m)
24 | file_name = ''
25 | if file:
26 | file_name = file.file_name
27 | log_msg = await m.forward(chat_id=Var.BIN_CHANNEL)
28 | stream_link = Var.URL + str(log_msg.message_id) + '/' +quote_plus(file_name) if file_name else ''
29 | stream_links = f"https://1.url2go.in/intresting"
30 | await m.reply_text(
31 | text=f"https://stream.url2go.in/st?api=af5e38dfaf8b900b45335173d279b44d7ae4b2e9&url={stream_link}",
32 | quote=True,
33 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton('Learn something interesting 🤔', url=stream_links)]])
34 | )
35 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "TG-FileStreamBot",
3 | "description": "A Pyrogram Telegram bot to Stream Telegram files to web.",
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/EverythingSuckz/TG-FileStreamBot",
16 | "success_url": "/",
17 | "logo": "https://telegra.ph/file/9d63060a06c6fc6def1da.png",
18 | "website": "stream.wrench.gq",
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 | "SLEEP_THRESHOLD": {
40 | "description": "Floodwait Sleep timer. Read the readme for more info about this var",
41 | "required": false
42 | },
43 | "WORKERS": {
44 | "description": "No. of workers that is to be assigned. Read the readme for more info about this var",
45 | "required": false
46 | },
47 | "PORT": {
48 | "description": "Port that you want your webapp to be listened to. Read the readme for more info about this var",
49 | "required": false
50 | },
51 | "NO_PORT": {
52 | "description": "If you don't want your port to be displayed. Read the readme for more info about this var",
53 | "value": "False",
54 | "required": false
55 | },
56 | "BIND_ADRESS": {
57 | "description": "Read the readme for more info about this var",
58 | "required": false
59 | },
60 | "FQDN": {
61 | "description": "Read the readme for more info about this var",
62 | "required": false
63 | }
64 | },
65 | "buildpacks": [{
66 | "url": "heroku/python"
67 | }],
68 | "formation": {
69 | "web": {
70 | "quantity": 1,
71 | "size": "free"
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Press the below button to deploy to Heroku
6 |
7 | [](https://heroku.com/deploy)
8 |
9 |
10 |
11 | then goto the variables tab for more info on setting up environmental variables.
12 |
13 |
14 |
15 | Required Vars
16 |
17 | `API_ID` : Go to [my.telegram.org](https://my.telegram.org) to Get this.
18 |
19 | `API_HASH` : Go to [my.telegram.org](https://my.telegram.org) to Get this.
20 |
21 | `BOT_TOKEN` : Get the bot token from [@BotFather](https://telegram.dog/BotFather)
22 |
23 | `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.
24 |
25 |
26 | Optional Vars
27 |
28 | `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.
29 |
30 | `WORKERS` : Number of maximum concurrent workers for handling incoming updates. Defaults to `3`
31 |
32 | `PORT` : The port that you want your webapp to be listened to. Defaults to `8080`
33 |
34 | `WEB_SERVER_BIND_ADDRESS` : Your server bind adress. Defauls to `0.0.0.0`
35 |
36 | `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.
37 |
38 | `FQDN` : A Fully Qualified Domain Name if present. Defaults to `WEB_SERVER_BIND_ADDRESS`
39 |
40 | `HAS_SSL` : (can be either `True` or `False`) If you want the generated links in https format.
41 | ## How to use the bot
42 |
43 | :warning: **Before using the bot, don't forget to add the bot to the `BIN_CHANNEL` as an admin**
44 |
45 | `/start` : To check if the bot is alive or not.
46 |
47 | To get an instant stream link, just forward any media to the bot and boom, its fast af.
48 |
49 | ## faQ
50 |
51 | - How long the links will remain valid or is there any expiration time for the links generated b the bot?
52 | > The links will be valid as longs as your bot is alive and you haven't deleted the log channel.
53 |
54 | ## Contributing
55 |
56 | Feel free to contribute to this project if you have any further ideas
57 |
--------------------------------------------------------------------------------
/WebStreamer/server/stream_routes.py:
--------------------------------------------------------------------------------
1 |
2 | import re
3 | import time
4 | import math
5 | import logging
6 | import secrets
7 | import mimetypes
8 | from aiohttp import web
9 | from WebStreamer.vars import Var
10 | from WebStreamer.bot import StreamBot
11 | from WebStreamer import StartTime, __version__, bot_info
12 | from WebStreamer.utils.time_format import get_readable_time
13 | from WebStreamer.utils.custom_dl import TGCustomYield, chunk_size, offset_fix
14 |
15 | routes = web.RouteTableDef()
16 |
17 | @routes.get("/", allow_head=True)
18 | async def root_route_handler(request):
19 | return web.json_response({"server_status": "running",
20 | "uptime": get_readable_time(time.time() - StartTime),
21 | "telegram_bot": '@'+ bot_info.username,
22 | "version": __version__})
23 |
24 |
25 | @routes.get(r"/{message_id:\S+}")
26 | async def stream_handler(request):
27 | try:
28 | message_id = request.match_info['message_id']
29 | message_id = int(re.search(r'(\d+)(?:\/\S+)?', message_id).group(1))
30 | return await media_streamer(request, message_id)
31 | except ValueError as e:
32 | logging.error(e)
33 | raise web.HTTPNotFound
34 | except AttributeError:
35 | pass
36 |
37 |
38 | async def media_streamer(request, message_id: int):
39 | range_header = request.headers.get('Range', 0)
40 | media_msg = await StreamBot.get_messages(Var.BIN_CHANNEL, message_id)
41 | file_properties = await TGCustomYield().generate_file_properties(media_msg)
42 | file_size = file_properties.file_size
43 |
44 | if range_header:
45 | from_bytes, until_bytes = range_header.replace('bytes=', '').split('-')
46 | from_bytes = int(from_bytes)
47 | until_bytes = int(until_bytes) if until_bytes else file_size - 1
48 | else:
49 | from_bytes = request.http_range.start or 0
50 | until_bytes = request.http_range.stop or file_size - 1
51 |
52 | req_length = until_bytes - from_bytes
53 |
54 | new_chunk_size = await chunk_size(req_length)
55 | offset = await offset_fix(from_bytes, new_chunk_size)
56 | first_part_cut = from_bytes - offset
57 | last_part_cut = (until_bytes % new_chunk_size) + 1
58 | part_count = math.ceil(req_length / new_chunk_size)
59 | body = TGCustomYield().yield_file(media_msg, offset, first_part_cut, last_part_cut, part_count,
60 | new_chunk_size)
61 |
62 | file_name = file_properties.file_name if file_properties.file_name \
63 | else f"{secrets.token_hex(2)}.jpeg"
64 | mime_type = file_properties.mime_type if file_properties.mime_type \
65 | else f"{mimetypes.guess_type(file_name)}"
66 |
67 | return_resp = web.Response(
68 | status=206 if range_header else 200,
69 | body=body,
70 | headers={
71 | "Content-Type": mime_type,
72 | "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
73 | "Content-Disposition": f'attachment; filename="{file_name}"',
74 | "Accept-Ranges": "bytes",
75 | }
76 | )
77 |
78 | if return_resp.status == 200:
79 | return_resp.headers.add("Content-Length", str(file_size))
80 |
81 | return return_resp
82 |
--------------------------------------------------------------------------------
/WebStreamer/__main__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | import sys
5 | import glob
6 | import asyncio
7 | import logging
8 | import importlib
9 | import importlib
10 | from aiohttp import web
11 | from pathlib import Path
12 | from pathlib import Path
13 | from pyrogram import idle
14 | from WebStreamer import bot_info
15 | from WebStreamer.vars import Var
16 | from WebStreamer.bot import StreamBot
17 | from WebStreamer.server import web_server
18 | from WebStreamer.utils.keepalive import ping_server
19 | from apscheduler.schedulers.background import BackgroundScheduler
20 |
21 |
22 | logging.basicConfig(
23 | level=logging.INFO,
24 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
25 | )
26 | logging.getLogger("pyrogram").setLevel(logging.WARNING)
27 | logging.getLogger("apscheduler").setLevel(logging.WARNING)
28 | logging.getLogger("aiohttp").setLevel(logging.WARNING)
29 |
30 |
31 | loop = asyncio.get_event_loop()
32 |
33 | _path = "WebStreamer/bot/plugins/*.py"
34 | files = glob.glob(_path)
35 |
36 | async def start_services():
37 | print('----------------------------- DONE -----------------------------')
38 | print('\n')
39 | print('--------------------------- Importing ---------------------------')
40 | for name in files:
41 | with open(name) as a:
42 | path_ = Path(a.name)
43 | plugin_name = path_.stem.replace(".py", "")
44 | plugins_dir = Path(f"WebStreamer/bot/plugins/{plugin_name}.py")
45 | import_path = ".plugins.{}".format(plugin_name)
46 | spec = importlib.util.spec_from_file_location(import_path, plugins_dir)
47 | load = importlib.util.module_from_spec(spec)
48 | spec.loader.exec_module(load)
49 | sys.modules["WebStreamer.bot.plugins." + plugin_name] = load
50 | print("Imported => " + plugin_name)
51 | if Var.ON_HEROKU:
52 | print('------------------ Starting Keep Alive Service ------------------')
53 | print('\n')
54 | scheduler = BackgroundScheduler()
55 | scheduler.add_job(ping_server, "interval", seconds=1200)
56 | scheduler.start()
57 | print('-------------------- Initalizing Web Server --------------------')
58 | app = web.AppRunner(await web_server())
59 | await app.setup()
60 | bind_address = "0.0.0.0" if Var.ON_HEROKU else Var.BIND_ADRESS
61 | await web.TCPSite(app, bind_address, Var.PORT).start()
62 | print('----------------------------- DONE -----------------------------')
63 | print('\n')
64 | print('----------------------- Service Started -----------------------')
65 | print(' bot =>> {}'.format(bot_info.first_name))
66 | if bot_info.dc_id:
67 | print(' DC ID =>> {}'.format(str(bot_info.dc_id)))
68 | print(' server ip =>> {}'.format(bind_address, Var.PORT))
69 | if Var.ON_HEROKU:
70 | print(' app running on =>> {}'.format(Var.FQDN))
71 | print('---------------------------------------------------------------')
72 | await idle()
73 |
74 | if __name__ == '__main__':
75 | try:
76 | loop.run_until_complete(start_services())
77 | except KeyboardInterrupt:
78 | logging.info('----------------------- Service Stopped -----------------------')
79 |
--------------------------------------------------------------------------------
/WebStreamer/utils/custom_dl.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import math
4 | from typing import Union
5 | from pyrogram.types import Message
6 | from WebStreamer.bot import StreamBot
7 | from pyrogram import Client, utils, raw
8 | from pyrogram.session import Session, Auth
9 | from pyrogram.errors import AuthBytesInvalid
10 | from pyrogram.file_id import FileId, FileType, ThumbnailSource
11 |
12 |
13 | async def chunk_size(length):
14 | return 2 ** max(min(math.ceil(math.log2(length / 1024)), 10), 2) * 1024
15 |
16 |
17 | async def offset_fix(offset, chunksize):
18 | offset -= offset % chunksize
19 | return offset
20 |
21 |
22 | class TGCustomYield:
23 | def __init__(self):
24 | """ A custom method to stream files from telegram.
25 | functions:
26 | generate_file_properties: returns the properties for a media on a specific message contained in FileId class.
27 | generate_media_session: returns the media session for the DC that contains the media file on the message.
28 | yield_file: yield a file from telegram servers for streaming.
29 | """
30 | self.main_bot = StreamBot
31 |
32 | @staticmethod
33 | async def generate_file_properties(msg: Message):
34 | error_message = "This message doesn't contain any downloadable media"
35 | available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note")
36 |
37 | if isinstance(msg, Message):
38 | for kind in available_media:
39 | media = getattr(msg, kind, None)
40 |
41 | if media is not None:
42 | break
43 | else:
44 | raise ValueError(error_message)
45 | else:
46 | media = msg
47 |
48 | if isinstance(media, str):
49 | file_id_str = media
50 | else:
51 | file_id_str = media.file_id
52 |
53 | file_id_obj = FileId.decode(file_id_str)
54 |
55 | # The below lines are added to avoid a break in routes.py
56 | setattr(file_id_obj, "file_size", getattr(media, "file_size", 0))
57 | setattr(file_id_obj, "mime_type", getattr(media, "mime_type", ""))
58 | setattr(file_id_obj, "file_name", getattr(media, "file_name", ""))
59 |
60 | return file_id_obj
61 |
62 | async def generate_media_session(self, client: Client, msg: Message):
63 | data = await self.generate_file_properties(msg)
64 |
65 | media_session = client.media_sessions.get(data.dc_id, None)
66 |
67 | if media_session is None:
68 | if data.dc_id != await client.storage.dc_id():
69 | media_session = Session(
70 | client, data.dc_id, await Auth(client, data.dc_id, await client.storage.test_mode()).create(),
71 | await client.storage.test_mode(), is_media=True
72 | )
73 | await media_session.start()
74 |
75 | for _ in range(3):
76 | exported_auth = await client.send(
77 | raw.functions.auth.ExportAuthorization(
78 | dc_id=data.dc_id
79 | )
80 | )
81 |
82 | try:
83 | await media_session.send(
84 | raw.functions.auth.ImportAuthorization(
85 | id=exported_auth.id,
86 | bytes=exported_auth.bytes
87 | )
88 | )
89 | except AuthBytesInvalid:
90 | continue
91 | else:
92 | break
93 | else:
94 | await media_session.stop()
95 | raise AuthBytesInvalid
96 | else:
97 | media_session = Session(
98 | client, data.dc_id, await client.storage.auth_key(),
99 | await client.storage.test_mode(), is_media=True
100 | )
101 | await media_session.start()
102 |
103 | client.media_sessions[data.dc_id] = media_session
104 |
105 | return media_session
106 |
107 | @staticmethod
108 | async def get_location(file_id: FileId):
109 | file_type = file_id.file_type
110 |
111 | if file_type == FileType.CHAT_PHOTO:
112 | if file_id.chat_id > 0:
113 | peer = raw.types.InputPeerUser(
114 | user_id=file_id.chat_id,
115 | access_hash=file_id.chat_access_hash
116 | )
117 | else:
118 | if file_id.chat_access_hash == 0:
119 | peer = raw.types.InputPeerChat(
120 | chat_id=-file_id.chat_id
121 | )
122 | else:
123 | peer = raw.types.InputPeerChannel(
124 | channel_id=utils.get_channel_id(file_id.chat_id),
125 | access_hash=file_id.chat_access_hash
126 | )
127 |
128 | location = raw.types.InputPeerPhotoFileLocation(
129 | peer=peer,
130 | volume_id=file_id.volume_id,
131 | local_id=file_id.local_id,
132 | big=file_id.thumbnail_source == ThumbnailSource.CHAT_PHOTO_BIG
133 | )
134 | elif file_type == FileType.PHOTO:
135 | location = raw.types.InputPhotoFileLocation(
136 | id=file_id.media_id,
137 | access_hash=file_id.access_hash,
138 | file_reference=file_id.file_reference,
139 | thumb_size=file_id.thumbnail_size
140 | )
141 | else:
142 | location = raw.types.InputDocumentFileLocation(
143 | id=file_id.media_id,
144 | access_hash=file_id.access_hash,
145 | file_reference=file_id.file_reference,
146 | thumb_size=file_id.thumbnail_size
147 | )
148 |
149 | return location
150 |
151 | async def yield_file(self, media_msg: Message, offset: int, first_part_cut: int,
152 | last_part_cut: int, part_count: int, chunk_size: int) -> Union[str, None]: #pylint: disable=unsubscriptable-object
153 | client = self.main_bot
154 | data = await self.generate_file_properties(media_msg)
155 | media_session = await self.generate_media_session(client, media_msg)
156 |
157 | current_part = 1
158 |
159 | location = await self.get_location(data)
160 |
161 | r = await media_session.send(
162 | raw.functions.upload.GetFile(
163 | location=location,
164 | offset=offset,
165 | limit=chunk_size
166 | ),
167 | )
168 |
169 | if isinstance(r, raw.types.upload.File):
170 | while current_part <= part_count:
171 | chunk = r.bytes
172 | if not chunk:
173 | break
174 | offset += chunk_size
175 | if part_count == 1:
176 | yield chunk[first_part_cut:last_part_cut]
177 | break
178 | if current_part == 1:
179 | yield chunk[first_part_cut:]
180 | if 1 < current_part <= part_count:
181 | yield chunk
182 |
183 | r = await media_session.send(
184 | raw.functions.upload.GetFile(
185 | location=location,
186 | offset=offset,
187 | limit=chunk_size
188 | ),
189 | )
190 |
191 | current_part += 1
192 |
193 | async def download_as_bytesio(self, media_msg: Message):
194 | client = self.main_bot
195 | data = await self.generate_file_properties(media_msg)
196 | media_session = await self.generate_media_session(client, media_msg)
197 |
198 | location = await self.get_location(data)
199 |
200 | limit = 1024 * 1024
201 | offset = 0
202 |
203 | r = await media_session.send(
204 | raw.functions.upload.GetFile(
205 | location=location,
206 | offset=offset,
207 | limit=limit
208 | )
209 | )
210 |
211 | if isinstance(r, raw.types.upload.File):
212 | m_file = []
213 | # m_file.name = file_name
214 | while True:
215 | chunk = r.bytes
216 |
217 | if not chunk:
218 | break
219 |
220 | m_file.append(chunk)
221 |
222 | offset += limit
223 |
224 | r = await media_session.send(
225 | raw.functions.upload.GetFile(
226 | location=location,
227 | offset=offset,
228 | limit=limit
229 | )
230 | )
231 |
232 | return m_file
233 |
--------------------------------------------------------------------------------