from fastapi import FastAPI, HTTPException, Request, Query from fastapi.responses import JSONResponse import logging import os from typing import List from LoadBalancer import LoadBalancer from utils import is_valid_url from urllib.parse import unquote CACHE_DIR = os.getenv("CACHE_DIR") TOKEN = os.getenv("TOKEN") REPO = os.getenv("REPO") app = FastAPI() @app.on_event("startup") async def startup_event(): global load_balancer load_balancer = LoadBalancer(cache_dir=CACHE_DIR, token=TOKEN, repo=REPO) @app.get("/") def greet_json(): return {"Version": load_balancer.version} @app.post("/api/post/register") async def register_instance(request: Request): try: data = await request.json() if not data or "url" not in data: return JSONResponse(content={"error": "No URL provided"}, status_code=400) url = data["url"] if not is_valid_url(url): return JSONResponse(content={"error": "Invalid URL"}, status_code=400) # Register the instance load_balancer.register_instance(url) logging.info(f"Instance registered: {url}") return JSONResponse(content={"message": f"Instance {url} registered successfully"}, status_code=200) except Exception as e: logging.error(f"Error registering instance: {e}") return JSONResponse(content={"error": "Failed to register instance"}, status_code=500) @app.get("/api/get/file_structure") async def get_file_structure(): return load_balancer.file_structure @app.get("/api/get/music/store") async def get_music_store(): return load_balancer.MUSIC_STORE @app.get("/api/get/music/all") async def get_all_music_api( page: int = Query(None, ge=1), # Default to None, but must be at least 1 if provided limit: int = Query(None, ge=1, le=100) # Default to None, but must be between 1 and 100 if provided ): # Fetch all music files from the load balancer all_music = load_balancer.get_all_music() # If pagination parameters are not provided, return all music if page is None or limit is None: return {"total_files": len(all_music), "files": all_music} # Calculate the starting index and the end index for pagination start_index = (page - 1) * limit end_index = start_index + limit # Handle the case where the requested page exceeds available files if start_index >= len(all_music): raise HTTPException(status_code=404, detail="No more files available for the requested page.") # Get the paginated music files paginated_music = all_music[start_index:end_index] # Prepare the response return { "page": page, "limit": limit, "total_files": len(all_music), "files": paginated_music } @app.get('/api/get/instances') async def get_instances(): return load_balancer.instances @app.get('/api/get/instances/health') async def get_instances_health(): return load_balancer.instances_health @app.get("/api/get/music/{file_name}") async def get_music_api(file_name: str): """Endpoint to get the music file by title.""" # Decode the file_name from URL encoding decoded_file_name = unquote(file_name) if not decoded_file_name: raise HTTPException(status_code=400, detail="file_name parameter is required") # Check if the music file is already cached if decoded_file_name in load_balancer.MUSIC_STORE: url = load_balancer.MUSIC_STORE[decoded_file_name] return JSONResponse(content={"url": url}) music_path = load_balancer.find_music_path(decoded_file_name) if not music_path: raise HTTPException(status_code=404, detail="Music file not found") # Start the download in an instance response = load_balancer.download_music_to_best_instance(file_name=decoded_file_name) if response: return JSONResponse(content=response) @app.get('/api/get/category/all') async def get_categories(): return load_balancer.get_all_categories() @app.get("/api/get/category/{category}") async def get_all_from_a_category( category: str, page: int = Query(1, ge=1), # Default to page 1, minimum value is 1 limit: int = Query(10, ge=1, le=100) # Default limit is 10, max limit is 100 ): if not category: raise HTTPException(status_code=400, detail="category parameter is required") # Fetch all files from the category all_files = load_balancer.get_files_from_category(category) # Calculate the starting index and the end index for pagination start_index = (page - 1) * limit end_index = start_index + limit # Get the paginated files paginated_files = all_files[start_index:end_index] # Prepare the response return { "page": page, "limit": limit, "total_files": len(all_files), "files": paginated_files }