From 97f7eb06742e1aa39a937022c08b80c88eca53b1 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 30 Sep 2025 02:14:14 +0000 Subject: [PATCH] Changes for API/UI --- unshackle/commands/serve.py | 10 +++++----- unshackle/core/api/__init__.py | 4 ++-- unshackle/core/api/routes.py | 29 +++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/unshackle/commands/serve.py b/unshackle/commands/serve.py index eaad5fe..515cd45 100644 --- a/unshackle/commands/serve.py +++ b/unshackle/commands/serve.py @@ -5,7 +5,7 @@ import click from aiohttp import web from unshackle.core import binaries -from unshackle.core.api import setup_routes, setup_swagger +from unshackle.core.api import cors_middleware, setup_routes, setup_swagger from unshackle.core.config import config from unshackle.core.constants import context_settings @@ -68,10 +68,10 @@ def serve(host: str, port: int, caddy: bool, api_only: bool, no_key: bool) -> No # API-only mode: serve just the REST API log.info("Starting REST API server (pywidevine CDM disabled)") if no_key: - app = web.Application() + app = web.Application(middlewares=[cors_middleware]) app["config"] = {"users": []} else: - app = web.Application(middlewares=[pywidevine_serve.authentication]) + app = web.Application(middlewares=[cors_middleware, pywidevine_serve.authentication]) app["config"] = {"users": [api_secret]} setup_routes(app) setup_swagger(app) @@ -85,11 +85,11 @@ def serve(host: str, port: int, caddy: bool, api_only: bool, no_key: bool) -> No # Create integrated app with both pywidevine and API routes if no_key: - app = web.Application() + app = web.Application(middlewares=[cors_middleware]) app["config"] = dict(config.serve) app["config"]["users"] = [] else: - app = web.Application(middlewares=[pywidevine_serve.authentication]) + app = web.Application(middlewares=[cors_middleware, pywidevine_serve.authentication]) # Setup config - add API secret to users for authentication serve_config = dict(config.serve) if not serve_config.get("users"): diff --git a/unshackle/core/api/__init__.py b/unshackle/core/api/__init__.py index 1fa2c9b..8369876 100644 --- a/unshackle/core/api/__init__.py +++ b/unshackle/core/api/__init__.py @@ -1,3 +1,3 @@ -from unshackle.core.api.routes import setup_routes, setup_swagger +from unshackle.core.api.routes import cors_middleware, setup_routes, setup_swagger -__all__ = ["setup_routes", "setup_swagger"] +__all__ = ["setup_routes", "setup_swagger", "cors_middleware"] diff --git a/unshackle/core/api/routes.py b/unshackle/core/api/routes.py index c8dfa7a..5445c87 100644 --- a/unshackle/core/api/routes.py +++ b/unshackle/core/api/routes.py @@ -4,17 +4,30 @@ from aiohttp import web from aiohttp_swagger3 import SwaggerDocs, SwaggerInfo, SwaggerUiSettings from unshackle.core import __version__ -from unshackle.core.api.handlers import ( - download_handler, - list_titles_handler, - list_tracks_handler, - list_download_jobs_handler, - get_download_job_handler, - cancel_download_job_handler, -) +from unshackle.core.api.handlers import (cancel_download_job_handler, download_handler, get_download_job_handler, + list_download_jobs_handler, list_titles_handler, list_tracks_handler) from unshackle.core.services import Services from unshackle.core.update_checker import UpdateChecker + +@web.middleware +async def cors_middleware(request: web.Request, handler): + """Add CORS headers to all responses.""" + # Handle preflight requests + if request.method == "OPTIONS": + response = web.Response() + else: + response = await handler(request) + + # Add CORS headers + response.headers["Access-Control-Allow-Origin"] = "*" + response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS" + response.headers["Access-Control-Allow-Headers"] = "Content-Type, X-API-Key, Authorization" + response.headers["Access-Control-Max-Age"] = "3600" + + return response + + log = logging.getLogger("api")