File size: 2,780 Bytes
07fd3f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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,
        )