"""YouTube relay diagnostics: source + FFmpeg + target watch URL layers.""" from __future__ import annotations import time from typing import Any from web2_quality_guard import build_youtube_quality_guard_report, parse_ffmpeg_metrics def _source_configured(url_lines: str) -> bool: for raw in str(url_lines or "").splitlines(): t = raw.strip() if not t or t.startswith("#"): continue if "douyin" in t.lower() or "live.douyin.com" in t.lower(): return True return False def build_youtube_diagnostics_report( rows: list[dict[str, Any]], *, config_by_process: dict[str, dict[str, str]] | None = None, ) -> dict[str, Any]: config_by_process = config_by_process or {} guard = build_youtube_quality_guard_report(rows, config_by_process=config_by_process) lanes: list[dict[str, Any]] = [] target_ok = 0 source_ok = 0 ffmpeg_ok = 0 for lane in guard.get("lanes") or []: proc = str(lane.get("process") or "") cfg = config_by_process.get(proc) or {} watch = str(cfg.get("watch_url") or "").strip() src_cfg = _source_configured(cfg.get("url_lines", "")) pushing = bool(lane.get("is_pushing")) metrics = lane.get("metrics") if isinstance(lane.get("metrics"), dict) else {} if not metrics and pushing: metrics = parse_ffmpeg_metrics( str((rows[0] if rows else {}).get("recent_log") or ""), ) issues = list(lane.get("issues") or []) score = int(lane.get("score") or 0) if src_cfg: source_ok += 1 else: issues.append({"level": "warning", "text": "源站地址未配置"}) score = max(0, score - 12) if watch: target_ok += 1 else: issues.append({"level": "warning", "text": "未配置 YouTube 目标监听地址"}) score = max(0, score - 8) ffmpeg_active = bool(lane.get("ffmpeg_active")) if pushing and ffmpeg_active: ffmpeg_ok += 1 elif pushing and not ffmpeg_active: issues.append({"level": "critical", "text": "推流中但未检测到 FFmpeg 进程"}) lanes.append( { **lane, "score": max(0, min(100, score)), "issues": issues[:8], "layers": { "source": { "ok": src_cfg, "hint": lane.get("source_url") or "", }, "ffmpeg": { "ok": ffmpeg_active or not pushing, "pushing": pushing, "metrics": metrics, }, "target": { "ok": bool(watch), "watch_url": watch, }, }, } ) lane_count = len(lanes) overall = int(sum(l["score"] for l in lanes) / lane_count) if lane_count else 0 return { **guard, "score": max(0, min(100, overall)), "lanes": lanes, "diagnostics": { "generated_at": time.time(), "layers": ["source", "ffmpeg", "target"], "summary": { "lanes": lane_count, "source_configured": source_ok, "target_configured": target_ok, "ffmpeg_active": ffmpeg_ok, }, }, }