Files
mcma-backend/app/main.py
T
Senko-san c7e078d758
Docker Build & Publish / build (push) Successful in 1m8s
Docker Build & Publish / push (push) Failing after 6s
Docker Build & Publish / Prune old image versions (push) Has been skipped
feat(config): derive MusicBrainz/AcoustID User-Agent from app name+version
Replace the placeholder MUSICBRAINZ_USER_AGENT env var with
MUSICBRAINZ_OWNER_EMAIL. The User-Agent ("MCMA/<version> ( <contact> )")
is now composed from the fixed app name, the installed package version,
and the operator's contact email — falling back to the project URL when
no email is configured. Also use the same version for the FastAPI app.
2026-06-11 00:39:24 +03:00

58 lines
1.6 KiB
Python

"""FastAPI composition root: wiring, lifespan, middleware, routers."""
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI, WebSocket
from app.api.errors import register_exception_handlers
from app.api.health import router as health_router
from app.api.middleware import CorrelationIdMiddleware
from app.api.rest import subsonic_router
from app.api.v1 import api_v1_router
from app.core.config import app_version, get_settings
from app.core.logging import configure_logging, get_logger
from app.infrastructure.cache import close_redis
from app.infrastructure.db import dispose_engine
log = get_logger(__name__)
@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
settings = get_settings()
log.info("startup", environment=settings.environment)
yield
log.info("shutdown")
await dispose_engine()
await close_redis()
def create_app() -> FastAPI:
settings = get_settings()
configure_logging(level=settings.log_level, json=settings.log_json)
app = FastAPI(
title="mcma-backend",
version=app_version(),
summary="Self-hosted, offline-first music service.",
lifespan=lifespan,
)
app.add_middleware(CorrelationIdMiddleware)
register_exception_handlers(app)
app.include_router(health_router)
app.include_router(api_v1_router)
app.include_router(subsonic_router, prefix="/rest")
@app.websocket("/ws")
async def ws_stub(websocket: WebSocket) -> None:
await websocket.accept()
await websocket.close(1001)
return app
app = create_app()