from __future__ import annotations from pathlib import Path from ..config import BASE_DIR, USE_OFFLINE_LIBS # Notatka: jeden manifest utrzymuje spójne adresy CDN i ścieżki lokalne dla trybu offline. LIBS_STATIC_DIR = "libs" LIBS_DIR = BASE_DIR / "pytorrent" / "static" / LIBS_STATIC_DIR BOOTSTRAP_VERSION = "5.3.3" BOOTSWATCH_VERSION = "5.3.3" FONTAWESOME_VERSION = "6.5.2" FLAG_ICONS_VERSION = "7.2.3" SWAGGER_UI_VERSION = "5" SOCKET_IO_VERSION = "4.7.5" BOOTSTRAP_THEMES = ( "default", "flatly", "litera", "lumen", "minty", "sketchy", "solar", "spacelab", "united", "zephyr", ) STATIC_ASSETS = { "bootstrap_js": { "local": f"{LIBS_STATIC_DIR}/bootstrap/{BOOTSTRAP_VERSION}/js/bootstrap.bundle.min.js", "cdn": f"https://cdn.jsdelivr.net/npm/bootstrap@{BOOTSTRAP_VERSION}/dist/js/bootstrap.bundle.min.js", }, "fontawesome_css": { "local": f"{LIBS_STATIC_DIR}/fontawesome/{FONTAWESOME_VERSION}/css/all.min.css", "cdn": f"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/{FONTAWESOME_VERSION}/css/all.min.css", }, "flag_icons_css": { "local": f"{LIBS_STATIC_DIR}/flag-icons/{FLAG_ICONS_VERSION}/css/flag-icons.min.css", "cdn": f"https://cdn.jsdelivr.net/gh/lipis/flag-icons@{FLAG_ICONS_VERSION}/css/flag-icons.min.css", }, "socket_io_js": { "local": f"{LIBS_STATIC_DIR}/socket.io/{SOCKET_IO_VERSION}/socket.io.min.js", "cdn": f"https://cdn.socket.io/{SOCKET_IO_VERSION}/socket.io.min.js", }, "swagger_css": { "local": f"{LIBS_STATIC_DIR}/swagger-ui/{SWAGGER_UI_VERSION}/swagger-ui.css", "cdn": f"https://cdn.jsdelivr.net/npm/swagger-ui-dist@{SWAGGER_UI_VERSION}/swagger-ui.css", }, "swagger_js": { "local": f"{LIBS_STATIC_DIR}/swagger-ui/{SWAGGER_UI_VERSION}/swagger-ui-bundle.js", "cdn": f"https://cdn.jsdelivr.net/npm/swagger-ui-dist@{SWAGGER_UI_VERSION}/swagger-ui-bundle.js", }, } def bootstrap_css_asset(theme: str | None = None) -> dict[str, str]: theme = theme if theme in BOOTSTRAP_THEMES else "default" if theme == "default": return { "local": f"{LIBS_STATIC_DIR}/bootstrap/{BOOTSTRAP_VERSION}/css/bootstrap.min.css", "cdn": f"https://cdn.jsdelivr.net/npm/bootstrap@{BOOTSTRAP_VERSION}/dist/css/bootstrap.min.css", } return { "local": f"{LIBS_STATIC_DIR}/bootswatch/{BOOTSWATCH_VERSION}/{theme}/bootstrap.min.css", "cdn": f"https://cdn.jsdelivr.net/npm/bootswatch@{BOOTSWATCH_VERSION}/dist/{theme}/bootstrap.min.css", } def asset_path(key: str) -> str: return STATIC_ASSETS[key]["local" if USE_OFFLINE_LIBS else "cdn"] def bootstrap_css_path(theme: str | None = None) -> str: return bootstrap_css_asset(theme)["local" if USE_OFFLINE_LIBS else "cdn"] def required_offline_paths() -> list[Path]: paths = [LIBS_DIR.parent / item["local"] for item in STATIC_ASSETS.values()] paths.extend(LIBS_DIR.parent / bootstrap_css_asset(theme)["local"] for theme in BOOTSTRAP_THEMES) return paths def missing_offline_paths() -> list[Path]: missing = [path for path in required_offline_paths() if not path.is_file() or path.stat().st_size <= 0] # Notatka: sprawdzane są też zasoby referencjonowane przez CSS, np. fonty ikon i pliki flag. required_dirs = [ LIBS_DIR / f"fontawesome/{FONTAWESOME_VERSION}/webfonts", LIBS_DIR / f"flag-icons/{FLAG_ICONS_VERSION}/flags/4x3", LIBS_DIR / f"flag-icons/{FLAG_ICONS_VERSION}/flags/1x1", ] for directory in required_dirs: if not directory.is_dir() or not any(directory.iterdir()): missing.append(directory) return missing def validate_offline_assets() -> None: # Notatka: aplikacja zatrzymuje start, gdy tryb offline jest aktywny, a pliki nie są zainstalowane. if not USE_OFFLINE_LIBS: return missing = missing_offline_paths() if missing: preview = "\n".join(f"- {path.relative_to(BASE_DIR)}" for path in missing[:20]) extra = "" if len(missing) <= 20 else f"\n- ... and {len(missing) - 20} more" raise RuntimeError( "PYTORRENT_USE_OFFLINE_LIBS=true, but frontend libraries are missing. " "Run: ./scripts/download_frontend_libs.py or ./install.sh\n" f"Missing files:\n{preview}{extra}" )