Safer ffmpeg kill, POST process/service actions, ARM encoder from hardware.env, filter_threads scaling

Made-with: Cursor
This commit is contained in:
eric
2026-03-28 12:03:13 -05:00
parent f4794e720a
commit 9b6570d06e
7 changed files with 204 additions and 45 deletions

38
web.py
View File

@@ -6,6 +6,8 @@ from contextlib import asynccontextmanager
from pathlib import Path
from typing import Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI, Query, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse, Response
@@ -315,6 +317,14 @@ async def run_service_action(
return JSONResponse({"error": str(exc)}, status_code=400)
@app.post("/service_action")
async def run_service_action_post(body: ServiceActionPostBody):
try:
return await service_action(body.service, body.action)
except (KeyError, ValueError) as exc:
return JSONResponse({"error": str(exc)}, status_code=400)
@app.get("/managed_roots")
async def get_managed_roots():
return {"roots": list_root_summaries()}
@@ -465,6 +475,15 @@ async def save_url_config(request: Request, process: str = Query(..., descriptio
return JSONResponse({"error": f"保存失败: {str(e)}"}, status_code=500)
class ProcessNameBody(BaseModel):
process: str = Field(..., min_length=1, max_length=160)
class ServiceActionPostBody(BaseModel):
service: str = Field(..., min_length=1, max_length=64)
action: str = Field(..., pattern="^(start|stop|restart)$")
def _not_found_hint(process: str) -> str:
if process_backend.mode == "local":
return (
@@ -486,6 +505,11 @@ async def start(process: str = Query(..., description="进程名")):
return JSONResponse({"output": output})
@app.post("/start")
async def start_post(body: ProcessNameBody):
return await start(process=body.process)
@app.get("/stop")
async def stop(process: str = Query(..., description="进程名")):
if process not in VALID_PROCESSES:
@@ -496,7 +520,7 @@ async def stop(process: str = Query(..., description="进程名")):
await asyncio.sleep(2.0)
if not process.startswith("web"):
await force_kill_ffmpeg(process)
await force_kill_ffmpeg(process, BASE_DIR)
await asyncio.sleep(1.0)
@@ -509,6 +533,11 @@ async def stop(process: str = Query(..., description="进程名")):
)
@app.post("/stop")
async def stop_post(body: ProcessNameBody):
return await stop(process=body.process)
@app.get("/restart")
async def restart(process: str = Query(..., description="进程名")):
if process not in VALID_PROCESSES:
@@ -518,10 +547,15 @@ async def restart(process: str = Query(..., description="进程名")):
return JSONResponse({"output": "内部错误:找不到脚本映射"}, status_code=500)
output = await process_backend.restart(process, sc)
if not process.startswith("web"):
await force_kill_ffmpeg(process)
await force_kill_ffmpeg(process, BASE_DIR)
return JSONResponse({"output": output})
@app.post("/restart")
async def restart_post(body: ProcessNameBody):
return await restart(process=body.process)
@app.get("/status")
async def status(process: str = Query(..., description="进程名")):
if process not in VALID_PROCESSES: