site: add server section, highlights carousel, OBT/Season content
- server status cards (online/players/version) via /api/status mcstatus ping - highlights carousel ported from old site (/highlights/ static media) - OBT (war in Zarya, open beta event server) + Season (Prologue, Create: Aeronautics, year-long) sections - nav updated, sections renumbered 01-06
This commit is contained in:
@@ -53,6 +53,9 @@ SITE_DIR = Path(__file__).parent / "site"
|
||||
# SkinRestorer skins (shared with TG bot)
|
||||
SKINS_DIR = Path("/root/python/site/skins")
|
||||
|
||||
# Minecraft server status (same host the TG bot pings)
|
||||
MC_STATUS_HOST = os.environ.get("MC_STATUS_HOST", "mc.zernmc.ru")
|
||||
|
||||
# Mirror configuration
|
||||
LAUNCHER_MIRRORS = {
|
||||
"main": "https://api.zern.cc", # primary
|
||||
@@ -966,6 +969,11 @@ for sub in ("css", "js", "img"):
|
||||
mount_dir.mkdir(parents=True, exist_ok=True)
|
||||
app.mount(f"/{sub}", StaticFiles(directory=mount_dir), name=f"site-{sub}")
|
||||
|
||||
# Server highlights media (screenshots / clips for the landing carousel)
|
||||
HIGHLIGHTS_DIR = SITE_DIR / "highlights"
|
||||
HIGHLIGHTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
app.mount("/highlights", StaticFiles(directory=HIGHLIGHTS_DIR), name="site-highlights")
|
||||
|
||||
|
||||
# Monkey patch to catch invalid HTTP requests
|
||||
original_data_received = HttpToolsProtocol.data_received
|
||||
@@ -1054,6 +1062,44 @@ async def get_skin(filename: str, request: Request):
|
||||
raise HTTPException(status_code=500, detail="Ошибка чтения скина")
|
||||
|
||||
|
||||
@app.get("/api/status")
|
||||
async def api_server_status():
|
||||
"""Live Minecraft server status via mcstatus ping (same host as TG bot)"""
|
||||
try:
|
||||
from mcstatus import JavaServer
|
||||
server = JavaServer.lookup(f"{MC_STATUS_HOST}")
|
||||
status = await server.async_status()
|
||||
|
||||
players_list = []
|
||||
try:
|
||||
query = await server.async_query()
|
||||
if query.players.names:
|
||||
players_list = query.players.names
|
||||
elif query.players.online > 0 and query.players.sample:
|
||||
players_list = [p.name for p in query.players.sample]
|
||||
except Exception:
|
||||
if status.players.sample:
|
||||
players_list = [p.name for p in status.players.sample]
|
||||
|
||||
version = getattr(status.version, "name", None) or "unknown"
|
||||
motd = status.description
|
||||
|
||||
return {
|
||||
"online": True,
|
||||
"players_online": status.players.online,
|
||||
"players_max": status.players.max,
|
||||
"players_list": ", ".join(players_list) if players_list else "никого нет",
|
||||
"players": players_list,
|
||||
"motd": motd,
|
||||
"version": version if isinstance(version, str) else str(version),
|
||||
"updated": datetime.now().strftime("%H:%M:%S")
|
||||
}
|
||||
except asyncio.TimeoutError:
|
||||
return {"online": False, "error": "Таймаут подключения к серверу", "updated": datetime.now().strftime("%H:%M:%S")}
|
||||
except Exception as e:
|
||||
return {"online": False, "error": f"{type(e).__name__}: {e}", "updated": datetime.now().strftime("%H:%M:%S")}
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
"""Health check endpoint"""
|
||||
|
||||
Reference in New Issue
Block a user