This commit is contained in:
eric
2026-03-24 14:47:03 -05:00
parent b914f0947a
commit efcec61d36
64 changed files with 22242 additions and 32 deletions

105
web2.py
View File

@@ -4,6 +4,7 @@ from pathlib import Path
import asyncio
import html
import os
from contextlib import asynccontextmanager
from typing import Optional
from fastapi.middleware.cors import CORSMiddleware
@@ -26,8 +27,27 @@ from web2_youtube_oauth import (
oauth_status as youtube_oauth_status_snapshot,
)
from web2_wechat_chatbot import register_wechat_chatbot_routes
from web2_client_overview import build_client_overview
from web2_relay_pro import (
build_relay_live_status,
ensure_default_relay_config,
first_youtube_pm2_name,
get_channel_detail,
list_channels_for_pro,
read_url_config_for_channel,
sync_channel_to_legacy_files,
update_channel_key,
write_url_config_for_channel,
)
app = FastAPI(title="多进程录制控制台")
@asynccontextmanager
async def lifespan(app: FastAPI):
ensure_default_relay_config(CONFIG_DIR)
yield
app = FastAPI(title="多进程录制控制台", lifespan=lifespan)
# ---------------- 配置(根目录结构) ----------------
BASE_DIR = Path(__file__).parent
@@ -187,6 +207,89 @@ app.add_middleware(
register_wechat_chatbot_routes(app, BASE_DIR)
@app.get("/client/overview")
async def client_overview():
"""Electron 工作台频道列表、微信摘要EasyTier 节点由主进程 easytier-cli 查询)。"""
return build_client_overview(CONFIG_DIR, BASE_DIR)
# ---------------- Pro 多路转播(每频道独立 URL 文件 + 去重 + 同步 legacy ----------------
@app.get("/relay_pro/channels")
async def relay_pro_channels():
return list_channels_for_pro(CONFIG_DIR)
@app.get("/relay_pro/channel_detail")
async def relay_pro_channel_detail(channel_id: str = Query(..., description="频道 id如 ch_0")):
d = get_channel_detail(CONFIG_DIR, channel_id)
if not d:
return JSONResponse({"error": "未找到频道"}, status_code=404)
return d
@app.get("/relay_pro/url_config")
async def relay_pro_get_url_config(channel_id: str = Query(...)):
return {"content": read_url_config_for_channel(CONFIG_DIR, channel_id)}
@app.post("/relay_pro/url_config")
async def relay_pro_post_url_config(request: Request, channel_id: str = Query(...)):
try:
data = await request.json()
except Exception:
return JSONResponse({"error": "无效的 JSON"}, status_code=400)
content = data.get("content", "") if isinstance(data, dict) else ""
ok, msg = write_url_config_for_channel(CONFIG_DIR, channel_id, content)
if not ok:
return JSONResponse({"error": msg}, status_code=400)
return {"message": msg}
@app.post("/relay_pro/channel_key")
async def relay_pro_save_channel_key(request: Request):
try:
data = await request.json()
except Exception:
return JSONResponse({"error": "无效的 JSON"}, status_code=400)
if not isinstance(data, dict):
return JSONResponse({"error": "无效数据"}, status_code=400)
cid = str(data.get("channelId") or data.get("channel_id") or "").strip()
key = str(data.get("youtubeKey") or data.get("key") or "")
if not cid:
return JSONResponse({"error": "缺少 channelId"}, status_code=400)
ok, msg = update_channel_key(CONFIG_DIR, cid, key)
if not ok:
return JSONResponse({"error": msg}, status_code=400)
return {"message": msg}
@app.post("/relay_pro/sync_active")
async def relay_pro_sync_active(channel_id: str = Query(...)):
ok, msg = sync_channel_to_legacy_files(CONFIG_DIR, channel_id)
if not ok:
return JSONResponse({"error": msg}, status_code=400)
return {"message": msg}
@app.get("/relay_pro/live_status")
async def relay_pro_live_status():
yt = first_youtube_pm2_name([{"script": e["script"]} for e in SCRIPT_ENTRIES])
async def read_tail(path: str, lines: int) -> str:
return await read_log_path(path, lines)
return await build_relay_live_status(
CONFIG_DIR,
BASE_DIR,
control_get_process_info,
read_tail,
yt,
)
# ---------------- 工具函数 ----------------
async def read_log_path(path: str, lines: int) -> str:
if not path: