mirror of
https://github.com/avipatilpro/FileStreamBot.git
synced 2026-01-16 06:42:54 -03:00
Updated ?
Nothing new but, looks like something changed ;) !
This commit is contained in:
7
FileStream/server/__init__.py
Normal file
7
FileStream/server/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from aiohttp import web
|
||||
from .stream_routes import routes
|
||||
|
||||
def web_server():
|
||||
web_app = web.Application(client_max_size=30000000)
|
||||
web_app.add_routes(routes)
|
||||
return web_app
|
||||
5
FileStream/server/exceptions.py
Normal file
5
FileStream/server/exceptions.py
Normal file
@@ -0,0 +1,5 @@
|
||||
class InvalidHash(Exception):
|
||||
message = "Invalid hash"
|
||||
|
||||
class FIleNotFound(Exception):
|
||||
message = "File not found"
|
||||
136
FileStream/server/stream_routes.py
Normal file
136
FileStream/server/stream_routes.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import time
|
||||
import math
|
||||
import logging
|
||||
import mimetypes
|
||||
import traceback
|
||||
from aiohttp import web
|
||||
from aiohttp.http_exceptions import BadStatusLine
|
||||
from FileStream.bot import multi_clients, work_loads, FileStream
|
||||
from FileStream.config import Telegram, Server
|
||||
from FileStream.server.exceptions import FIleNotFound, InvalidHash
|
||||
from FileStream import utils, StartTime, __version__
|
||||
from FileStream.utils.render_template import render_page
|
||||
|
||||
routes = web.RouteTableDef()
|
||||
|
||||
@routes.get("/status", allow_head=True)
|
||||
async def root_route_handler(_):
|
||||
return web.json_response(
|
||||
{
|
||||
"server_status": "running",
|
||||
"uptime": utils.get_readable_time(time.time() - StartTime),
|
||||
"telegram_bot": "@" + FileStream.username,
|
||||
"connected_bots": len(multi_clients),
|
||||
"loads": dict(
|
||||
("bot" + str(c + 1), l)
|
||||
for c, (_, l) in enumerate(
|
||||
sorted(work_loads.items(), key=lambda x: x[1], reverse=True)
|
||||
)
|
||||
),
|
||||
"version": __version__,
|
||||
}
|
||||
)
|
||||
|
||||
@routes.get("/watch/{path}", allow_head=True)
|
||||
async def stream_handler(request: web.Request):
|
||||
try:
|
||||
path = request.match_info["path"]
|
||||
return web.Response(text=await render_page(path), content_type='text/html')
|
||||
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
|
||||
|
||||
|
||||
@routes.get("/dl/{path}", allow_head=True)
|
||||
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))
|
||||
|
||||
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]
|
||||
|
||||
if Telegram.MULTI_CLIENT:
|
||||
logging.info(f"Client {index} is now serving {request.headers.get('X-FORWARDED-FOR',request.remote)}")
|
||||
|
||||
if faster_client in class_cache:
|
||||
tg_connect = class_cache[faster_client]
|
||||
logging.debug(f"Using cached ByteStreamer object for client {index}")
|
||||
else:
|
||||
logging.debug(f"Creating new ByteStreamer object for client {index}")
|
||||
tg_connect = utils.ByteStreamer(faster_client)
|
||||
class_cache[faster_client] = tg_connect
|
||||
logging.debug("before calling get_file_properties")
|
||||
file_id = await tg_connect.get_file_properties(db_id, multi_clients)
|
||||
logging.debug("after calling get_file_properties")
|
||||
|
||||
file_size = file_id.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 = 1024 * 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, index, offset, first_part_cut, last_part_cut, part_count, chunk_size
|
||||
)
|
||||
|
||||
mime_type = file_id.mime_type
|
||||
file_name = utils.get_name(file_id)
|
||||
disposition = "attachment"
|
||||
|
||||
if not mime_type:
|
||||
mime_type = mimetypes.guess_type(file_name)[0] or "application/octet-stream"
|
||||
|
||||
# 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",
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user