This commit is contained in:
eric
2026-03-26 05:35:31 -05:00
parent bc6e550b95
commit cbe4585ff4
14 changed files with 78 additions and 41 deletions

View File

@@ -44,7 +44,6 @@
```bash
cd electron
pnpm install
pnpm run prepare-easytier # 下载 Windows easytier 二进制(可选,见 package.json
pnpm dev
```

View File

@@ -1 +1 @@
https://live.douyin.com/116645105013,主播: 张火火摆摊日记
https://live.douyin.com/11664523242

View File

@@ -1,5 +0,0 @@
{
"networkName": "lr_自动生成",
"networkSecret": "自动生成请勿手填",
"peerUrls": []
}

View File

@@ -1,3 +1 @@
# 每行一个抖音直播间地址,例如:
# https://live.douyin.com/123456789
https://live.douyin.com/11664523242

View File

@@ -1,2 +0,0 @@
https://live.douyin.com/28358181657,主播: 罗瑞和夜市_印度飞饼_(阿泽)

View File

@@ -1 +0,0 @@
# 每行一个抖音直播间地址

View File

@@ -1,5 +1,5 @@
[youtube]
key = ue78-1c3e-mr9g-14mz-9r4z
key = 112313123124124124124124124df
fast_audio = 1
output_resolution = 720p
use_gpu =

View File

@@ -1,7 +0,0 @@
[youtube]
key = h018-hqur-uhtv-5bt2-1x3q
fast_audio = 1
output_resolution = 720p
use_gpu =
audio_denoise =

View File

@@ -1,5 +1,5 @@
[youtube]
key = ue78-1c3e-mr9g-14mz-9r4z
key = 112313123124124124124124124df
fast_audio = 1
output_resolution = 720p
use_gpu =

View File

@@ -2,17 +2,11 @@
"version": 1,
"autoManaged": true,
"channels": [
{
"id": "ch_default",
"name": "默认线路",
"douyinUrl": "",
"youtubeKey": "ue78-1c3e-mr9g-14mz-9r4z"
},
{
"id": "ch_1774436412",
"name": "频道 2",
"douyinUrl": "",
"youtubeKey": ""
"youtubeKey": "112313123124124124124124124df"
},
{
"id": "ch_1774436414",
@@ -98,12 +92,6 @@
"douyinUrl": "",
"youtubeKey": ""
},
{
"id": "ch_1774438395",
"name": "频道 17",
"douyinUrl": "",
"youtubeKey": "h018-hqur-uhtv-5bt2-1x3q"
},
{
"id": "ch_1774439571",
"name": "频道 18",

25
web2.py
View File

@@ -46,8 +46,9 @@ from web2_relay_pro import (
write_url_config_for_channel,
)
from web2_youtube_ini import parse_youtube_ini, serialize_youtube_ini
from web2_host_caps import gpu_status_payload
from web2_host_caps import gpu_status_payload, machine_summary_payload
from web2_douyin_preview import fetch_douyin_anchor_name
from web2_pocketbase import REQUIRE_PB, pb_auth_refresh_and_validate
@asynccontextmanager
@@ -243,7 +244,7 @@ register_wechat_chatbot_routes(app, BASE_DIR)
@app.get("/client/overview")
async def client_overview():
"""Electron 工作台:频道列表、微信摘要EasyTier 节点由主进程 easytier-cli 查询)"""
"""Electron 工作台:频道列表、微信摘要。"""
return build_client_overview(CONFIG_DIR, BASE_DIR)
@@ -385,6 +386,12 @@ async def host_gpu_status():
return gpu_status_payload()
@app.get("/host/machine_summary")
async def host_machine_summary():
"""本机 hostname / OS / 架构等,供会员遥测写入 PocketBase。"""
return machine_summary_payload()
@app.post("/douyin/room_previews")
async def douyin_room_previews(request: Request):
try:
@@ -580,7 +587,12 @@ async def _stop_legacy_youtube_if_online() -> None:
# ---------------- PM2 控制路由 ----------------
@app.get("/start")
async def start(process: str = Query(..., description="进程名")):
async def start(request: Request, process: str = Query(..., description="进程名")):
if REQUIRE_PB:
tok = (request.headers.get("x-pb-token") or "").strip()
ok, msg, _ = await pb_auth_refresh_and_validate(tok)
if not ok:
return JSONResponse({"output": msg}, status_code=403)
if not process_valid(process):
return JSONResponse({"output": f"无效进程名: {process}"}, status_code=400)
cid = relay_channel_id_from_pm2_name(process)
@@ -633,7 +645,12 @@ async def stop(process: str = Query(..., description="进程名")):
@app.get("/restart")
async def restart(process: str = Query(..., description="进程名")):
async def restart(request: Request, process: str = Query(..., description="进程名")):
if REQUIRE_PB:
tok = (request.headers.get("x-pb-token") or "").strip()
ok, msg, _ = await pb_auth_refresh_and_validate(tok)
if not ok:
return JSONResponse({"output": msg}, status_code=403)
if not process_valid(process):
return JSONResponse({"output": f"无效进程名: {process}"}, status_code=400)
cid = relay_channel_id_from_pm2_name(process)

View File

@@ -1,5 +1,5 @@
"""
工作台 /client/overviewYouTube 频道摘要、微信绑定摘要EasyTier 节点数由 Electron 主进程补充)
工作台 /client/overviewYouTube 频道摘要、微信绑定摘要。
多路转播语义:每条线路为「一个抖音直播间 ↔ 一个 YouTube 串流」一对一;
禁止同一抖音直播间同时向多个 YouTube 频道推流;禁止多条线路共用同一串流密钥(避免串台)。
@@ -251,5 +251,4 @@ def build_client_overview(config_dir: Path, base_dir: Path) -> dict[str, Any]:
"relayValidationErrors": relay_errors,
"relayNotes": relay_notes,
"wechat": wechat,
"easyTierPeersNote": "peer 数量由 Electron 调用 easytier-cli peer list 获取",
}

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
import platform
import socket
import subprocess
from typing import Any
@@ -39,3 +40,14 @@ def gpu_status_payload() -> dict[str, Any]:
"nvidia_detected": nv,
"nvenc_available": enc,
}
def machine_summary_payload() -> dict[str, Any]:
"""供远程 App 遥测:本机标识与系统信息。"""
return {
"hostname": socket.gethostname(),
"os": platform.system(),
"os_release": platform.release(),
"machine": platform.machine(),
"python": platform.python_version(),
}

39
web2_pocketbase.py Normal file
View File

@@ -0,0 +1,39 @@
"""PocketBase校验用户令牌与 live_allowed供 /start /restart 可选强制。"""
from __future__ import annotations
import os
from typing import Any, Tuple
import httpx
PB_URL = os.environ.get("WEB2_PB_URL", "https://pocketbase.hackrobot.cn").rstrip("/")
REQUIRE_PB = os.environ.get("WEB2_REQUIRE_PB_AUTH", "").strip().lower() in ("1", "true", "yes")
async def pb_auth_refresh_and_validate(token: str) -> Tuple[bool, str, dict[str, Any]]:
"""
使用 auth-refresh 校验令牌并拉取最新用户记录。
返回 (ok, error_message, record)
"""
t = (token or "").strip()
if not t:
return False, "缺少 PocketBase 授权(请在手机端登录会员账号)", {}
url = f"{PB_URL}/api/collections/users/auth-refresh"
try:
async with httpx.AsyncClient(timeout=20.0) as client:
r = await client.post(url, headers={"Authorization": f"Bearer {t}"})
except Exception as e:
return False, f"PocketBase 不可达: {e}", {}
try:
data = r.json()
except Exception:
return False, "PocketBase 响应无效", {}
if r.status_code != 200:
msg = str(data.get("message") or "授权无效或已过期")
return False, msg, {}
rec = data.get("record") or {}
if not isinstance(rec, dict):
return False, "用户记录异常", {}
if rec.get("live_allowed") is False:
return False, "账号已被管理员停用远程直播权限", {}
return True, "", rec