mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-02-20 07:59:50 -05:00
189 lines
5.8 KiB
Python
189 lines
5.8 KiB
Python
import logging
|
|
import os
|
|
|
|
import uvicorn
|
|
from fastapi import APIRouter, FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.staticfiles import StaticFiles
|
|
from psycopg.errors import UniqueViolation
|
|
from sqlalchemy.exc import IntegrityError
|
|
from starlette.responses import FileResponse, RedirectResponse, Response
|
|
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
|
|
|
import media_manager.movies.router as movies_router
|
|
import media_manager.torrent.router as torrent_router
|
|
import media_manager.tv.router as tv_router
|
|
from media_manager.auth.router import (
|
|
auth_metadata_router,
|
|
get_openid_router,
|
|
)
|
|
from media_manager.auth.router import (
|
|
users_router as custom_users_router,
|
|
)
|
|
from media_manager.auth.schemas import UserCreate, UserRead, UserUpdate
|
|
from media_manager.auth.users import (
|
|
bearer_auth_backend,
|
|
cookie_auth_backend,
|
|
fastapi_users,
|
|
)
|
|
from media_manager.config import MediaManagerConfig
|
|
from media_manager.exceptions import (
|
|
ConflictError,
|
|
InvalidConfigError,
|
|
MediaAlreadyExistsError,
|
|
NotFoundError,
|
|
conflict_error_handler,
|
|
invalid_config_error_exception_handler,
|
|
media_already_exists_exception_handler,
|
|
not_found_error_exception_handler,
|
|
sqlalchemy_integrity_error_handler,
|
|
)
|
|
from media_manager.filesystem_checks import run_filesystem_checks
|
|
from media_manager.logging import LOGGING_CONFIG, setup_logging
|
|
from media_manager.notification.router import router as notification_router
|
|
from media_manager.scheduler import setup_scheduler
|
|
|
|
setup_logging()
|
|
|
|
config = MediaManagerConfig()
|
|
log = logging.getLogger(__name__)
|
|
|
|
if config.misc.development:
|
|
log.warning("Development Mode activated!")
|
|
|
|
scheduler = setup_scheduler(config)
|
|
|
|
run_filesystem_checks(config, log)
|
|
|
|
BASE_PATH = os.getenv("BASE_PATH", "")
|
|
FRONTEND_FILES_DIR = os.getenv("FRONTEND_FILES_DIR")
|
|
DISABLE_FRONTEND_MOUNT = os.getenv("DISABLE_FRONTEND_MOUNT", "").lower() == "true"
|
|
FRONTEND_FOLLOW_SYMLINKS = os.getenv("FRONTEND_FOLLOW_SYMLINKS", "").lower() == "true"
|
|
|
|
log.info("Hello World!")
|
|
app = FastAPI(root_path=BASE_PATH)
|
|
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
|
|
origins = config.misc.cors_urls
|
|
log.info(f"CORS URLs activated for following origins: {origins}")
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=origins,
|
|
allow_credentials=True,
|
|
allow_methods=["GET", "PUT", "POST", "DELETE", "PATCH", "HEAD", "OPTIONS"],
|
|
)
|
|
api_app = APIRouter(prefix="/api/v1")
|
|
|
|
|
|
@api_app.get("/health")
|
|
async def hello_world() -> dict:
|
|
return {"message": "Hello World!", "version": os.getenv("PUBLIC_VERSION")}
|
|
|
|
|
|
api_app.include_router(
|
|
fastapi_users.get_auth_router(bearer_auth_backend),
|
|
prefix="/auth/jwt",
|
|
tags=["auth"],
|
|
)
|
|
api_app.include_router(
|
|
fastapi_users.get_auth_router(cookie_auth_backend),
|
|
prefix="/auth/cookie",
|
|
tags=["auth"],
|
|
)
|
|
api_app.include_router(
|
|
fastapi_users.get_register_router(UserRead, UserCreate),
|
|
prefix="/auth",
|
|
tags=["auth"],
|
|
)
|
|
api_app.include_router(
|
|
fastapi_users.get_reset_password_router(), prefix="/auth", tags=["auth"]
|
|
)
|
|
api_app.include_router(
|
|
fastapi_users.get_verify_router(UserRead), prefix="/auth", tags=["auth"]
|
|
)
|
|
api_app.include_router(custom_users_router, tags=["users"])
|
|
api_app.include_router(
|
|
fastapi_users.get_users_router(UserRead, UserUpdate),
|
|
prefix="/users",
|
|
tags=["users"],
|
|
)
|
|
api_app.include_router(auth_metadata_router, tags=["openid"])
|
|
|
|
if get_openid_router():
|
|
api_app.include_router(get_openid_router(), tags=["openid"], prefix="/auth/oauth")
|
|
|
|
api_app.include_router(tv_router.router, prefix="/tv", tags=["tv"])
|
|
api_app.include_router(torrent_router.router, prefix="/torrent", tags=["torrent"])
|
|
api_app.include_router(movies_router.router, prefix="/movies", tags=["movie"])
|
|
api_app.include_router(
|
|
notification_router, prefix="/notification", tags=["notification"]
|
|
)
|
|
|
|
# serve static image files
|
|
app.mount(
|
|
"/api/v1/static/image",
|
|
StaticFiles(directory=config.misc.image_directory),
|
|
name="static-images",
|
|
)
|
|
app.include_router(api_app)
|
|
|
|
# handle static frontend files
|
|
if not DISABLE_FRONTEND_MOUNT:
|
|
app.mount(
|
|
"/web",
|
|
StaticFiles(
|
|
directory=FRONTEND_FILES_DIR,
|
|
html=True,
|
|
follow_symlink=FRONTEND_FOLLOW_SYMLINKS,
|
|
),
|
|
name="frontend",
|
|
)
|
|
log.debug(f"Mounted frontend at /web from {FRONTEND_FILES_DIR}")
|
|
else:
|
|
log.info("Frontend mounting disabled (DISABLE_FRONTEND_MOUNT is set)")
|
|
|
|
|
|
@app.get("/")
|
|
async def root():
|
|
return RedirectResponse(url="/web/")
|
|
|
|
|
|
@app.get("/dashboard")
|
|
async def dashboard():
|
|
return RedirectResponse(url="/web/")
|
|
|
|
|
|
@app.get("/login")
|
|
async def login():
|
|
return RedirectResponse(url="/web/")
|
|
|
|
|
|
# this will serve the custom 404 page for frontend routes, so SvelteKit can handle routing
|
|
@app.exception_handler(404)
|
|
async def not_found_handler(request, _exc):
|
|
if not DISABLE_FRONTEND_MOUNT and any(
|
|
base_path in ["/web", "/dashboard", "/login"] for base_path in request.url.path
|
|
):
|
|
return FileResponse(f"{FRONTEND_FILES_DIR}/404.html")
|
|
return Response(content="Not Found", status_code=404)
|
|
|
|
|
|
# Register exception handlers for custom exceptions
|
|
app.add_exception_handler(NotFoundError, not_found_error_exception_handler)
|
|
app.add_exception_handler(
|
|
MediaAlreadyExistsError, media_already_exists_exception_handler
|
|
)
|
|
app.add_exception_handler(InvalidConfigError, invalid_config_error_exception_handler)
|
|
app.add_exception_handler(IntegrityError, sqlalchemy_integrity_error_handler)
|
|
app.add_exception_handler(UniqueViolation, sqlalchemy_integrity_error_handler)
|
|
app.add_exception_handler(ConflictError, conflict_error_handler)
|
|
|
|
if __name__ == "__main__":
|
|
uvicorn.run(
|
|
app,
|
|
host="127.0.0.1",
|
|
port=5049,
|
|
log_config=LOGGING_CONFIG,
|
|
proxy_headers=True,
|
|
forwarded_allow_ips="*",
|
|
)
|