diff --git a/api/frontend_api.py b/api/frontend_api.py index 4722bcb..506f059 100644 --- a/api/frontend_api.py +++ b/api/frontend_api.py @@ -10,13 +10,15 @@ from utils import const from utils.network import get_user_data, get_user_public_ip # Create a router with more appropriate naming for the frontend -router = APIRouter(prefix="/api/v1", tags=["frontend"]) +router = APIRouter() # ---- Data Models ---- + class AppConfig(BaseModel): """Base configuration data for the application""" + addon_name: str logo_url: str host_url: str @@ -31,18 +33,21 @@ class AppConfig(BaseModel): class UserConfig(BaseModel): """User-specific configuration data""" + user_data: Dict[str, Any] configured_fields: List[str] class ValidationResult(BaseModel): """Data model for validation results""" + status: str message: Optional[str] = None class StreamData(BaseModel): """Data model for stream information""" + title: str year: int poster: str @@ -59,6 +64,7 @@ class StreamData(BaseModel): # ---- API Endpoints ---- + @router.get("/app-config", response_model=AppConfig) async def get_app_config(): """ @@ -75,7 +81,8 @@ async def get_app_config(): "branding_description": settings.branding_description, "is_public_instance": settings.is_public_instance, "disabled_providers": settings.disabled_providers, - "authentication_required": settings.api_password is not None and not settings.is_public_instance, + "authentication_required": settings.api_password is not None + and not settings.is_public_instance, } @@ -97,7 +104,9 @@ async def get_user_config( configured_fields.extend(["provider_token", "password"]) if user_data.streaming_provider.qbittorrent_config: - user_data.streaming_provider.qbittorrent_config.qbittorrent_password = "••••••••" + user_data.streaming_provider.qbittorrent_config.qbittorrent_password = ( + "••••••••" + ) user_data.streaming_provider.qbittorrent_config.webdav_password = "••••••••" configured_fields.extend(["qbittorrent_password", "webdav_password"]) @@ -132,8 +141,13 @@ async def get_system_constants(): } -@router.get("/download/{secret_str}/{catalog_type}/{video_id}", response_model=StreamData) -@router.get("/download/{secret_str}/{catalog_type}/{video_id}/{season}/{episode}", response_model=StreamData) +@router.get( + "/download/{secret_str}/{catalog_type}/{video_id}", response_model=StreamData +) +@router.get( + "/download/{secret_str}/{catalog_type}/{video_id}/{season}/{episode}", + response_model=StreamData, +) async def get_download_info( request: Request, secret_str: str, diff --git a/api/main.py b/api/main.py index 5043c8a..49454f3 100644 --- a/api/main.py +++ b/api/main.py @@ -960,5 +960,5 @@ app.include_router(metrics_router, prefix="/metrics", tags=["metrics"]) app.include_router(kodi_router, prefix="/kodi", tags=["kodi"]) -# Add the frontend API router -app.include_router(frontend_api_router) + +app.include_router(frontend_api_router, prefix="/api/v1", tags=["frontend"]) diff --git a/utils/const.py b/utils/const.py index bbfdbcf..a7b74cd 100644 --- a/utils/const.py +++ b/utils/const.py @@ -98,6 +98,19 @@ USER_UPLOAD_SUPPORTED_SERIES_CATALOG_IDS = [ "telugu_series", ] +USER_UPLOAD_SUPPORTED_SPORTS_CATALOG_IDS = [ + "american_football", + "baseball", + "basketball", + "football", + "formula_racing", + "hockey", + "motogp_racing", + "rugby", + "other_sports", + "fighting", +] + RESOLUTIONS = [ "4k", "2160p", diff --git a/utils/validation_helper.py b/utils/validation_helper.py index 2113e4b..93585c5 100644 --- a/utils/validation_helper.py +++ b/utils/validation_helper.py @@ -4,6 +4,8 @@ import logging from urllib.parse import urlparse, urljoin import httpx +from fastapi import Depends, HTTPException +from fastapi.security import APIKeyHeader from db import schemas from db.config import settings @@ -11,6 +13,23 @@ from utils import const from utils.network import is_private_ip from db.redis_database import REDIS_ASYNC_CLIENT +# API Key Header for authentication +API_KEY_HEADER = APIKeyHeader(name="X-API-Key", auto_error=False) + + +async def api_password_dependency(api_key: str = Depends(API_KEY_HEADER)): + """Validate the API password from header or throw exception""" + if not settings.api_password: + return "no_password_required" + + if api_key != settings.api_password: + raise HTTPException( + status_code=401, + detail="Invalid API key", + headers={"WWW-Authenticate": "APIKey"}, + ) + return api_key + def is_valid_url(url: str) -> bool: parsed_url = urlparse(url)