ytptube/app/routes/api/_static.py
2026-01-03 17:39:22 +03:00

156 lines
4.4 KiB
Python

import logging
from pathlib import Path
import magic
from aiohttp import web
from aiohttp.web import Request, Response
from app.library.config import Config
from app.library.router import add_route
MIME = magic.Magic(mime=True)
LOG: logging.Logger = logging.getLogger(__name__)
STATIC_FILES: dict[str, dict] = {}
EXT_TO_MIME: dict = {
".html": "text/html",
".css": "text/css",
".js": "application/javascript",
".json": "application/json",
".ico": "image/x-icon",
".webmanifest": "application/manifest+json",
".m4a": "audio/mp4",
}
FRONTEND_ROUTES: list[str] = [
"/console/",
"/presets/",
"/tasks/",
"/task_definitions/",
"/notifications/",
"/changelog/",
"/logs/",
"/conditions/",
"/browser/",
"/simple/",
"/browser/{path:.*}",
]
async def serve_static_file(request: Request, config: Config) -> Response:
"""
Preload static files from the ui/exported folder.
Args:
request (Request): The request object.
config (Config): The configuration instance.
Returns:
Response: The response object.
"""
path: str = request.path
if "/" != config.base_path and path.startswith(config.base_path):
path = path.replace(config.base_path[:-1], "", 1)
if path not in STATIC_FILES:
for k in STATIC_FILES:
if path.startswith(k):
path = k
break
else:
return web.json_response({"error": "File not found.", "file": path}, status=web.HTTPNotFound.status_code)
item: dict = STATIC_FILES[path]
return web.FileResponse(
path=item["file"],
headers={
"Pragma": "public",
"Cache-Control": "public, max-age=31536000",
"Content-Type": item.get("content_type"),
},
status=web.HTTPOk.status_code,
)
def preload_static(root_path: Path, config: Config) -> None:
"""
Preload static files from the ui/exported folder.
Args:
root_path (Path): The root path of the application.
config (Config): The configuration instance.
"""
global STATIC_FILES # noqa: PLW0602
static_dir: Path | None = None
webui_files: list[Path] = [
(root_path / "ui" / "exported").absolute(),
(root_path.parent / "ui" / "exported").absolute(),
]
if config.static_ui_path:
webui_files = [Path(config.static_ui_path).absolute()]
for p in webui_files:
if p.exists():
static_dir = p
break
if static_dir is None:
webui_files = [str(p) for p in webui_files]
msg: str = f"Could not find the frontend UI static assets in '{webui_files=}'."
raise ValueError(msg)
preloaded = 0
for file in static_dir.rglob("*.*"):
if ".map" == file.suffix:
continue
uri_path: str = f"/{file.relative_to(static_dir).as_posix()!s}"
contentType = EXT_TO_MIME.get(file.suffix)
if not contentType:
contentType = MIME.from_file(str(file))
STATIC_FILES[uri_path] = {
"uri": uri_path,
"content_type": contentType,
"file": file,
}
add_route(method="GET", path=uri_path, handler=serve_static_file)
preloaded += 1
if "/index.html" in STATIC_FILES:
for path in FRONTEND_ROUTES:
STATIC_FILES[path] = STATIC_FILES["/index.html"]
STATIC_FILES[path.lstrip("/")] = STATIC_FILES["/index.html"]
add_route(method="GET", path=path, handler=serve_static_file)
LOG.debug(f"Preloading frontend static route '{path}'.")
preloaded += 1
# Add main app route
STATIC_FILES["/"] = STATIC_FILES["/index.html"]
STATIC_FILES[config.base_path] = STATIC_FILES["/index.html"]
add_route(method="GET", path=config.base_path, handler=serve_static_file, name="index")
if "/" != config.base_path:
async def redirect_index(config: Config) -> web.Response:
return web.Response(status=web.HTTPFound.status_code, headers={"Location": config.base_path})
add_route(method="GET", path="/", handler=redirect_index, name="index_redirect")
if preloaded < 1:
message: str = f"Failed to find any static files in '{static_dir}'."
if config.ignore_ui:
LOG.warning(message)
return
raise ValueError(message)
LOG.info(f"Loaded '{preloaded}' static files.")