import traceback import math from aiohttp import web import config from pyrogram.file_id import FileId from aiohttp.http_exceptions import BadStatusLine from YukkiMusic import app, userbot from YukkiMusic.core.bot import YukkiBot from YukkiMusic.core.userbot import multi_clients, req_client from YukkiMusic.platforms.custom_dl import ByteStreamer class InvalidHash(Exception): message = "Invalid hash" class FIleNotFound(Exception): message = "File not found" class_cache={} async def media_streamer(request: web.Request, db_id: str): range_header = request.headers.get("Range", 0) #index = min(work_loads, key=work_loads.get) #faster_client = multi_clients[index] client=app #client = await req_client() #get_me = await app.get_me() #print(db_id,int(config.LOG_GROUP_ID),get_me) msg = await client.get_messages(int(config.LOG_GROUP_ID),int(db_id)) #print(msg) #tg_connect = ByteStreamer(client['client']) tg_connect = ByteStreamer(client) #class_cache[client['client']] = tg_connect #logging.debug("before calling get_file_properties") file_info = get_file_info(msg) #file_i = file_info['file']['file_id'] file_id = FileId.decode(file_info['file']['file_id']) #print(file_id) #logging.debug("after calling get_file_properties") file_size = file_info['file']['file_size'] if range_header: from_bytes, until_bytes = range_header.replace("bytes=", "").split("-") from_bytes = int(from_bytes) until_bytes = int(until_bytes) if until_bytes else file_size - 1 else: from_bytes = request.http_range.start or 0 until_bytes = (request.http_range.stop or file_size) - 1 if (until_bytes > file_size) or (from_bytes < 0) or (until_bytes < from_bytes): return web.Response( status=416, body="416: Range not satisfiable", headers={"Content-Range": f"bytes */{file_size}"}, ) chunk_size = 512 * 1024 until_bytes = min(until_bytes, file_size - 1) offset = from_bytes - (from_bytes % chunk_size) first_part_cut = from_bytes - offset last_part_cut = until_bytes % chunk_size + 1 req_length = until_bytes - from_bytes + 1 part_count = math.ceil(until_bytes / chunk_size) - math.floor( offset / chunk_size) body = tg_connect.yield_file(file_id, client, offset, first_part_cut, last_part_cut, part_count, chunk_size) mime_type = file_info['file']['mime_type'] file_name = get_name(msg) disposition = "attachment" # if "video/" in mime_type or "audio/" in mime_type: # disposition = "inline" return web.Response( status=206 if range_header else 200, body=body, headers={ "Content-Type": f"{mime_type}", "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}", "Content-Length": str(req_length), "Content-Disposition": f'{disposition}; filename="{file_name}"', "Accept-Ranges": "bytes", }, ) async def stream_handler(request: web.Request): try: path = request.match_info["path"] return await media_streamer(request, path) except InvalidHash as e: raise web.HTTPForbidden(text=e.message) except FIleNotFound as e: raise web.HTTPNotFound(text=e.message) except (AttributeError, BadStatusLine, ConnectionResetError): pass except Exception as e: traceback.print_exc() #logging.critical(e.with_traceback(None)) #logging.debug(traceback.format_exc()) raise web.HTTPInternalServerError(text=str(e)) TGFILEAPI = web.Application() TGFILEAPI.router.add_get('/{path}', stream_handler)