import os import json import logging import asyncio import traceback import aiohttp_cors from aiohttp import web from pyrogram import raw from bson import ObjectId from bson.json_util import dumps from aiohttp.http_exceptions import BadStatusLine #---------------------Local Imports----------------------------------# from FileStream.bot import req_client from FileStream.config import Telegram, Server from FileStream.Database import Database from FileStream.TMDB.Endpoint import search_tmdb_any, search_tmdb_tv, search_tmdb_movies from FileStream.server.exceptions import FIleNotFound, InvalidHash from .Functions.downloader import media_streamer CORS_HEADERS = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "*" } async def handle_v2(request): return web.Response(text="Hello from app api!") # API endpoint to list 10 files (pagination optimization) async def list_10_all_files_db(request): db = Database(Telegram.DATABASE_URL, Telegram.SESSION_NAME) files, total_files = await db.find_all_files([1, 10]) return web.json_response([dict(file) async for file in files], headers=CORS_HEADERS) # API endpoint to list all files in database async def list_all_files_db(request): db = Database(Telegram.DATABASE_URL, Telegram.SESSION_NAME) files = await db.get_all_files_api() # Ensure `get_all_files_api` is optimized for performance return web.json_response(json.loads(dumps(files)), headers=CORS_HEADERS) # API endpoint to list all TMDB movies related to files in the database async def list_all_tmdb_movies_from_db(request): db = Database(Telegram.DATABASE_URL, Telegram.SESSION_NAME) files = await db.get_all_files() response = [] for row in files: try: resp = search_tmdb_movies(str(row['file']['caption']) if row['file']['caption'] else str(row['file']['file_name'])) if resp: response.append(resp) except Exception as e: logging.error(f"Error while fetching TMDB movie for {row['file']['caption']}: {e}") return web.json_response(json.loads(dumps(response)), headers=CORS_HEADERS) # API endpoint to list all TMDB TV shows related to files in the database async def list_all_tmdb_tv_from_db(request): db = Database(Telegram.DATABASE_URL, Telegram.SESSION_NAME) files = await db.get_all_files() response = [] for row in files: try: resp = search_tmdb_tv(str(row['file']['caption']) if row['file']['caption'] else str(row['file']['file_name'])) if resp: response.append(resp) except Exception as e: logging.error(f"Error while fetching TMDB TV show for {row['file']['caption']}: {e}") return web.json_response(json.loads(dumps(response)), headers=CORS_HEADERS) # API endpoint to list all TMDB results, streaming them to the client async def list_all_files_tmdb(request): db = Database(Telegram.DATABASE_URL, Telegram.SESSION_NAME) files = await db.get_all_files() async def data_generator(): for row in files: try: resp = search_tmdb_any(str(row['file']['caption']) if row['file']['caption'] else str(row['file']['file_name'])) if resp: yield json.dumps(resp) + '\n' # Streaming data to client in chunks except Exception as e: logging.error(f"Error while fetching TMDB data for {row['file']['caption']}: {e}") return web.Response(body=data_generator(), content_type='application/json', headers=CORS_HEADERS) # API endpoint to list all files for a simple response async def list_all_files(request): db = Database(Telegram.DATABASE_URL, Telegram.SESSION_NAME) files = await db.get_all_files_api() resp = [{ "adult": False, "backdrop_path": "/c1bz69r0v065TGFA5nqBiKzPDys.jpg", "genre_ids": [35, 10751, 10402], "id": f"{row['_id']}", "original_language": "en-hi", "original_title": f"{str(row['file']['caption'])}", "overview": "XRepo Movies", "popularity": 1710.176, "poster_path": "/irIS5Tn3TXjNi1R9BpWvGAN4CZ1.jpg", "release_date": "2022-10-07", "title": f"{str(row['file']['caption'])}", "link": f"{Server.URL}api/dl/{row['_id']}", "vote_average": 7.8, "vote_count": 122, } for row in files] return web.json_response(json.loads(dumps(resp)), headers=CORS_HEADERS) # Upload endpoint with optimization (not reading entire file into memory) async def upload_file(request: web.Request): data = await request.post() file = data.get('file').file chunk = file.read() # Read the file in chunks to avoid memory overload file_details = dict( user_id="thebinary1", dropzone_id=str(data["dzuuid"]), file=dict( file_id=str(data["dzuuid"]), file_unique_id=str(data["dzuuid"]), file_name=str(data.get('file').filename), file_size=int(data["dztotalfilesize"]), mime_type=mime_identifier(str(data.get('file').filename)), part_size=int(data["dzchunksize"]), file_part=int(data["dzchunkindex"]), total_parts=int(data["dztotalchunkcount"]) ), time=Time_ISTKolNow(), user_type="WEB", privacy_type="PRIVATE" ) client_req = await req_client() # Ensure client request is fast and optimized tg_connect = TeleUploader(client_req["client"]) main = await tg_connect.upload_web_file(file_details, chunk) return web.json_response({ "status": main.get("status"), "message": main.get("message") }) # Stream file handler with optimized error handling async def stream_handler(request: web.Request): try: path = request.match_info["path"] return await media_streamer(request, path, "FAST") 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 # Handle expected errors silently except Exception as e: logging.error(f"Error while streaming file: {str(e)}") traceback.print_exc() raise web.HTTPInternalServerError(text=str(e)) # Web server setup with optimized CORS handling api = web.Application() cors = aiohttp_cors.setup(api, defaults={"*": aiohttp_cors.ResourceOptions( allow_credentials=False, expose_headers="*", allow_headers="*", allow_methods="*" )}) cors.add(api.router.add_get('/', handle_v2)) api.router.add_get('/files', list_all_files_db) api.router.add_get('/files/mix', list_all_files) api.router.add_get('/tmdb/mix', list_all_files_tmdb) api.router.add_get('/10/files', list_10_all_files_db) api.router.add_get('/tmdb/tv', list_all_tmdb_tv_from_db) api.router.add_get('/tmdb/movies', list_all_tmdb_movies_from_db) api.router.add_get('/upload', upload_file) api.router.add_get('/dl/{path}', stream_handler)