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
This commit is contained in:
admin committed 2026-08-07 15:02:07 +08:00
commit 2e4594fa77
43 files changed
+2196

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
import httpx
import asyncio
from config import settings
class MediaMTXService:
@staticmethod
def get_rtmp_url(stream_key: str) -> str:
return f"rtmp://{settings.media_origin_host}:{settings.media_origin_rtmp_port}/live/{stream_key}"
@staticmethod
def get_hls_url(node: dict, stream_key: str) -> str:
return f"http://{node['host']}:{node['hls_port']}/{stream_key}/index.m3u8"
@staticmethod
async def get_origin_status(stream_key: str) -> dict | None:
try:
async with httpx.AsyncClient(timeout=httpx.Timeout(5)) as client:
resp = await client.get(
f"http://{settings.media_origin_host}:{settings.media_origin_api_port}/v3/paths/list"
)
if resp.status_code == 200:
data = resp.json()
for item in data.get("items", []):
if item.get("name") == stream_key:
return {"ready": item.get("ready", False), "source_ready": item.get("sourceReady", False)}
except Exception:
return None
return None
@staticmethod
async def get_edge_status(node: dict, stream_key: str) -> dict | None:
try:
async with httpx.AsyncClient(timeout=httpx.Timeout(3)) as client:
resp = await client.get(
f"http://{node['host']}:{node['api_port']}/v3/paths/list"
)
if resp.status_code == 200:
data = resp.json()
for item in data.get("items", []):
if item.get("name") == stream_key:
return {"ready": item.get("ready", False), "readers": item.get("readersCount", 0)}
except Exception:
return None
return None
media_service = MediaMTXService()