This commit is contained in:
eric
2026-07-10 05:15:29 -05:00
parent a0104f6517
commit 924d05d06e
71 changed files with 6815 additions and 680 deletions

View File

@@ -10,8 +10,13 @@ import time
from pathlib import Path
from typing import Any, Callable, Awaitable
from web2_youtube_ini import parse_youtube_ini, serialize_youtube_ini
from web2_youtube_pro_runtime import (
channel_pm2_name,
default_youtube_pro_pm2_name,
normalize_youtube_pro_channels,
)
from web2_config_governance import backup_config_file
from web2_youtube_ini import parse_youtube_ini, serialize_youtube_ini
# 与 web2_client_overview 一致的去重键
def _norm_douyin_url(url: str) -> str:
@@ -181,6 +186,8 @@ def list_channels_for_pro(config_dir: Path) -> dict[str, Any]:
{
"id": cid,
"name": name,
"pm2Name": channel_pm2_name(item),
"notes": str(item.get("notes") or "").strip(),
"douyinUrl": durl,
"keyPreview": kp,
"youtubeWatchUrl": get_youtube_watch_url(config_dir, cid),
@@ -312,6 +319,9 @@ def get_channel_detail(config_dir: Path, channel_id: str) -> dict[str, Any] | No
return {
"id": str(ch.get("id") or "").strip(),
"name": str(ch.get("name") or "").strip() or "未命名",
"pm2Name": channel_pm2_name(ch),
"notes": str(ch.get("notes") or "").strip(),
"urlLines": str(ch.get("urlLines") or "").strip(),
"douyinUrl": str(ch.get("douyinUrl") or ch.get("douyin_url") or "").strip(),
"youtubeKey": active,
"youtubeKeys": keys,
@@ -368,16 +378,30 @@ def update_channel_keys_list(
return False, "未找到该频道"
_DOUYIN_LIVE_ROOM_RE = re.compile(
r"(?:https?://(?:www\.)?)?live\.douyin\.com/([a-zA-Z0-9_-]+)", re.IGNORECASE
)
def extract_douyin_url_from_config_line(line: str) -> str:
"""从 URL_config 行解析抖音直播间 URL兼容 d2ypp2url,主播: 名 / 原画,url,主播: 名)。"""
raw = (line or "").strip().lstrip("\ufeff")
if not raw or raw.startswith("#"):
return ""
m = _DOUYIN_LIVE_ROOM_RE.search(raw)
if m:
return f"https://live.douyin.com/{m.group(1)}"
return ""
def extract_url_lines_from_ini(text: str) -> list[str]:
lines: list[str] = []
seen: set[str] = set()
for raw in text.splitlines():
t = raw.strip()
if not t or t.startswith("#"):
continue
if "," in t:
t = t.split(",")[-1].strip()
if "douyin" in t.lower() or "v.douyin.com" in t.lower() or "live.douyin.com" in t.lower():
lines.append(t)
url = extract_douyin_url_from_config_line(raw)
if url and url not in seen:
seen.add(url)
lines.append(url)
return lines
@@ -448,6 +472,10 @@ def read_url_config_for_channel(config_dir: Path, channel_id: str) -> str:
def write_url_config_for_channel(config_dir: Path, channel_id: str, content: str) -> tuple[bool, str]:
if not extract_url_lines_from_ini(content):
existing = read_url_config_for_channel(config_dir, channel_id)
if extract_url_lines_from_ini(existing):
return False, "源站地址为空,已拒绝覆盖已有配置"
errs = validate_url_config_no_cross_duplicate(config_dir, channel_id, content)
if errs:
return False, errs[0]
@@ -517,8 +545,34 @@ def parse_relay_meta_lines(log_text: str) -> list[dict[str, Any]]:
return out
def relay_pm2_name_for_channel(channel_id: str) -> str:
return f"youtube2__{channel_id}"
def relay_pm2_name_for_channel(channel_id: str, config_dir: Path | None = None) -> str:
cfg = config_dir or Path("config")
ch = get_channel_by_id(cfg, channel_id)
if ch:
return channel_pm2_name(ch)
return default_youtube_pro_pm2_name(channel_id)
def save_channels_document(config_dir: Path, channels: list[dict[str, Any]]) -> tuple[bool, str]:
try:
normalized = normalize_youtube_pro_channels(channels)
except ValueError as exc:
return False, str(exc)
doc, errs = load_channels_document(config_dir)
if doc is None:
return False, errs[0] if errs else "无法读取配置"
doc["channels"] = normalized
channels_json_path(config_dir).write_text(json.dumps(doc, ensure_ascii=False, indent=2), encoding="utf-8")
return True, "已保存频道配置"
def channel_id_for_pm2_name(config_dir: Path, pm2: str) -> str:
doc, _ = load_channels_document(config_dir)
if not doc or not isinstance(doc.get("channels"), list):
return ""
from web2_youtube_pro_runtime import channel_id_for_pm2_name as _cid_for_pm2
return _cid_for_pm2(doc["channels"], pm2)
async def build_relay_live_status(
@@ -540,7 +594,7 @@ async def build_relay_live_status(
if not cid:
continue
cname = str(c.get("name") or "").strip() or "未命名"
pname = relay_pm2_name_for_channel(cid)
pname = relay_pm2_name_for_channel(cid, config_dir)
try:
info = await get_process_info(pname)
except Exception:
@@ -650,6 +704,8 @@ def add_relay_channel(
row: dict[str, Any] = {
"id": new_id,
"name": nm,
"pm2Name": default_youtube_pro_pm2_name(new_id),
"notes": "",
"douyinUrl": "",
"youtubeKey": key,
}