|
import math, asyncio, subprocess |
|
from telethon import TelegramClient |
|
from fastapi.responses import StreamingResponse |
|
|
|
import logging |
|
|
|
logging.getLogger(__name__) |
|
logging.basicConfig(level=logging.INFO) |
|
|
|
|
|
class Download: |
|
client: TelegramClient |
|
route: str |
|
offset: int |
|
handler: None |
|
file: None |
|
limit: int |
|
file_size: float |
|
|
|
def __init__(self, handler): |
|
self.handler = handler |
|
self.file = handler.message.media |
|
self.file_size = handler.message.file.size |
|
self.limit = handler.sanity.limit |
|
self.offset = handler.sanity.offset |
|
self.client = handler.client |
|
self.mime_type = handler.message.file.mime_type |
|
|
|
async def download(self): |
|
part_size = int(512 * 1024) * 2 |
|
first_part_cut = self.offset % part_size |
|
first_part = math.floor(self.offset / part_size) |
|
last_part_cut = part_size - (self.limit % part_size) |
|
last_part = math.ceil(self.limit / part_size) |
|
part_count = math.ceil(self.file_size / part_size) |
|
part = first_part |
|
try: |
|
async for chunk in self.client.iter_download( |
|
self.file, offset=first_part * part_size, request_size=part_size |
|
): |
|
if part == first_part: |
|
yield bytes(chunk[first_part_cut:]) |
|
elif part == last_part: |
|
yield bytes(chunk[:last_part_cut]) |
|
else: |
|
yield bytes(chunk) |
|
logging.debug(f"Part {part}/{last_part} (total {part_count}) served!") |
|
part += 1 |
|
logging.debug("serving finished") |
|
except (GeneratorExit, StopAsyncIteration, asyncio.CancelledError): |
|
logging.debug("file serve interrupted") |
|
|
|
raise |
|
except Exception as e: |
|
print(e) |
|
logging.debug("file serve errored", exc_info=True) |
|
|
|
async def handle_request(self): |
|
headers = { |
|
"content-type": self.mime_type, |
|
"content-range": f"bytes {self.offset}-{self.limit-1}/{self.file_size}", |
|
"content-length": str(self.limit - self.offset), |
|
"accept-ranges": "bytes", |
|
"content-transfer-encoding": "Binary", |
|
"content-disposition": f'{self.handler.route}; filename="{self.handler.message.file.name}"', |
|
} |
|
logging.info( |
|
f"Serving file in {self.handler.message.file.name}) ; Range: {self.offset} - {self.limit}" |
|
) |
|
if self.handler.head: |
|
body = None |
|
else: |
|
body = self.download() |
|
return StreamingResponse( |
|
media_type=self.mime_type, |
|
content=body, |
|
headers=headers, |
|
status_code=206 if self.offset else 200, |
|
) |
|
|