/** 与 Electron NetworkDashboard / SystemMetrics 对齐的数据结构 */ export type SiteInfo = { host: string reachable: boolean latency_ms: number error: string | null resolved_ip: string | null country: string | null country_code: string | null geo_error: string | null } export type SpeedBlock = { label: string download_mbps: number | null download_error: string | null download_bytes_sampled: number upload_mbps: number | null upload_error: string | null upload_target: string | null } export type NetworkPayload = { google: SiteInfo douyin: SiteInfo routes: { different: boolean | null; note: string } speed: { overseas: SpeedBlock; domestic: SpeedBlock } meta?: { at: number; download_cap_bytes: number; upload_bytes: number } error?: string } export type SystemMetricsPayload = { ts?: number cpu_percent?: number | null cpu_count_logical?: number memory?: { percent?: number; used?: number; total?: number; available?: number } swap?: { percent?: number; used?: number; total?: number } disks?: Array<{ mountpoint?: string percent?: number free?: number total?: number }> network?: { up_mbps?: number | null; down_mbps?: number | null } ffmpeg_processes?: Array<{ pid?: number; name?: string; rss?: number }> error?: string } export type ClientOverview = { youtubeChannelCount?: number youtubeChannels?: { name: string; keyPreview: string; douyinPreview?: string }[] relayPairingPolicy?: string relayValidationErrors?: string[] relayNotes?: string[] wechat?: { configured?: boolean nickName?: string wcId?: string online?: boolean proxyError?: string | null } } export type RelayLivePayload = { youtubeProcess?: string processStatus?: string processOnline?: boolean relayRows?: Array<{ channelId?: string | null channelName?: string anchor?: string douyinHint?: string streamTitle?: string youtubeKeySuffix?: string durationSec?: number | null processOnline?: boolean }> } export type YoutubeIniModel = { keys: string[] activeIndex: number options: Record header: string } export type GpuCaps = { nvidia_detected: boolean; nvenc_available: boolean }