Files
live/backend/main.py
T
admin 2e4594fa77 Initial commit: LiveStream Platform
Backend: FastAPI + SQLAlchemy + SQLite
Frontend: React + Vite + Ant Design (serif Anthropic theme)
Media server: MediaMTX with edge node support
Load balancing: round-robin / weighted / least-conn
Multicast detection with automatic fallback
Transcoding support via FFmpeg (configurable quality)
hls.js player with line & quality switching
Admin panel with password auth
Windows compatible scripts
2026-08-07 15:02:07 +08:00

67 lines
1.9 KiB
Python

import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from starlette.responses import RedirectResponse
from starlette.background import BackgroundTask
import httpx
from database import init_db
from services.transcoder import transcode_mgr
from routes import streams_router, nodes_router, auth_router
from config import settings
@asynccontextmanager
async def lifespan(app: FastAPI):
await init_db()
yield
transcode_mgr.stop_all()
app = FastAPI(title="LiveStream Platform", lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(streams_router)
app.include_router(nodes_router)
app.include_router(auth_router)
@app.get("/api/health")
async def health():
from services.multicast_detector import multicast_detector
return {
"status": "ok",
"multicast_available": multicast_detector.is_available(),
}
@app.get("/hls/{path:path}")
async def serve_hls(path: str):
hls_root = "/tmp/hls"
fs_path = os.path.join(hls_root, path)
if os.path.isfile(fs_path):
return FileResponse(fs_path)
target = f"http://127.0.0.1:{settings.media_origin_hls_port}/{path}"
try:
async with httpx.AsyncClient(timeout=httpx.Timeout(10)) as client:
req = client.build_request("GET", target)
resp = await client.send(req, stream=True)
from starlette.responses import StreamingResponse
return StreamingResponse(
resp.aiter_bytes(),
status_code=resp.status_code,
headers=dict(resp.headers),
media_type=resp.headers.get("content-type"),
)
except Exception:
raise HTTPException(status_code=404)