From b617555360b16448965fc8593a3f78d97a01fe0f Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 19 May 2026 09:19:52 +0000 Subject: [PATCH] s --- d2ypp2/scripts/linux/lib/common.sh | 61 ++++++-- d2ypp2/scripts/linux/service_ctl.sh | 49 ++++-- d2ypp2/services/neko/browser-launch.sh | 54 ++----- d2ypp2/services/neko/docker-compose.yml | 3 - .../manifest.json | 17 --- .../youtube-studio-auto-dismiss.js | 46 ------ d2ypp2/src/hub_kv_store.py | 7 +- d2ypp2/src/youtube_pro_runtime.py | 22 ++- d2ypp2/tests/test_neko_config.py | 77 ++++++++-- d2ypp2/tests/test_verify_local_install.py | 79 ++++++++++ d2ypp2/tests/test_web_dynamic_processes.py | 68 ++++++--- d2ypp2/tests/test_youtube_pro_runtime.py | 4 + d2ypp2/tools/render_neko_compose.py | 1 - d2ypp2/tools/verify_local_install.py | 141 +++++++++++++++++- .../live-product/LiveYoutubeUnmannedView.tsx | 11 +- d2ypp2/web-console/lib/youtubeProChannels.ts | 18 ++- d2ypp2/web-console/out/.build-stamp.json | 4 +- d2ypp2/web-console/out/404.html | 2 +- .../_buildManifest.js | 0 .../_ssgManifest.js | 0 .../chunks/app/page-10361036b8bf1ca2.js | 1 - .../chunks/app/page-3c5cf076d3a5e7c5.js | 1 + d2ypp2/web-console/out/android.html | 2 +- d2ypp2/web-console/out/android.txt | 2 +- d2ypp2/web-console/out/console.html | 2 +- d2ypp2/web-console/out/console.txt | 2 +- d2ypp2/web-console/out/index.html | 2 +- d2ypp2/web-console/out/index.txt | 4 +- d2ypp2/web-console/out/shellcrash.html | 2 +- d2ypp2/web-console/out/shellcrash.txt | 2 +- 30 files changed, 477 insertions(+), 207 deletions(-) delete mode 100644 d2ypp2/services/neko/youtube-auto-dismiss-extension/manifest.json delete mode 100644 d2ypp2/services/neko/youtube-auto-dismiss-extension/youtube-studio-auto-dismiss.js rename d2ypp2/web-console/out/_next/static/{z_UuUy3mGDwiCWfhwZJVM => UmN0Ou_Iv2TWI4xcHvY2X}/_buildManifest.js (100%) rename d2ypp2/web-console/out/_next/static/{z_UuUy3mGDwiCWfhwZJVM => UmN0Ou_Iv2TWI4xcHvY2X}/_ssgManifest.js (100%) delete mode 100644 d2ypp2/web-console/out/_next/static/chunks/app/page-10361036b8bf1ca2.js create mode 100644 d2ypp2/web-console/out/_next/static/chunks/app/page-3c5cf076d3a5e7c5.js diff --git a/d2ypp2/scripts/linux/lib/common.sh b/d2ypp2/scripts/linux/lib/common.sh index b0bf371..40857df 100755 --- a/d2ypp2/scripts/linux/lib/common.sh +++ b/d2ypp2/scripts/linux/lib/common.sh @@ -362,8 +362,13 @@ resolve_neko_profile_dir() { resolve_neko_profile_dir_for_instance() { local idx="${1:-1}" - local base + local base override base="${NEKO_PROFILE_HOST_DIR:-$(resolve_neko_profile_dir)}" + eval "override=\"\${NEKO_PROFILE_HOST_DIR_${idx}:-}\"" + if [ -n "$override" ]; then + printf '%s' "$override" + return 0 + fi case "$idx" in 1) printf '%s' "$base" ;; *) printf '%s-%s' "$base" "$idx" ;; @@ -541,8 +546,22 @@ neko_managed_policies_enabled() { esac } +copy_neko_tampermonkey_seed_dir() { + local src="${1:-}" dst="${2:-}" marker="${3:-}" + [ -e "$src" ] || return 0 + if [ -e "$dst" ]; then + if [ -z "$marker" ] || grep -R -a -q "$marker" "$dst" 2>/dev/null; then + return 0 + fi + rm -rf "$dst" 2>/dev/null || true + fi + mkdir -p "$(dirname "$dst")" + cp -a "$src" "$dst" 2>/dev/null || true + rm -f "$dst/LOCK" 2>/dev/null || true +} + seed_neko_tampermonkey_profile() { - local target="${1:-}" donor="${2:-}" rel src dst + local target="${1:-}" donor="${2:-}" rel src dst marker [ -n "$target" ] || return 0 if [ -z "$donor" ] || [ ! -d "$donor/Default/Extensions/dhdgffkkebhmkfjojejmpbldmpobfkfo" ]; then donor="$(find_neko_tampermonkey_seed_profile "$target")" @@ -555,21 +574,17 @@ seed_neko_tampermonkey_profile() { "Local Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo"; do src="$donor/Default/$rel" dst="$target/Default/$rel" - [ -e "$src" ] || continue - [ ! -e "$dst" ] || continue - mkdir -p "$(dirname "$dst")" - cp -a "$src" "$dst" 2>/dev/null || true - rm -f "$dst/LOCK" 2>/dev/null || true + marker="Tampermonkey" + case "$rel" in + "Local Extension Settings/"*) marker="YouTube Studio Auto Dismiss" ;; + esac + copy_neko_tampermonkey_seed_dir "$src" "$dst" "$marker" done rel="Managed Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo" src="$donor/Default/$rel" dst="$target/Default/$rel" if neko_managed_policies_enabled; then - if [ -e "$src" ] && [ ! -e "$dst" ]; then - mkdir -p "$(dirname "$dst")" - cp -a "$src" "$dst" 2>/dev/null || true - rm -f "$dst/LOCK" 2>/dev/null || true - fi + copy_neko_tampermonkey_seed_dir "$src" "$dst" "YouTube Studio Auto Dismiss" else rm -rf "$dst" 2>/dev/null || true fi @@ -626,7 +641,22 @@ if not isinstance(source, dict): raise SystemExit(0) target = load(target_pref) settings = target.setdefault("extensions", {}).setdefault("settings", {}) -if ext_id not in settings: + +def should_replace_current(value: object) -> bool: + if not isinstance(value, dict): + return True + if value.get("state") != 1: + return True + if value.get("from_webstore") is not True: + return True + path = str(value.get("path") or "") + if path.startswith("/"): + return True + if value.get("location") == 8: + return True + return False + +if should_replace_current(settings.get(ext_id)): settings[ext_id] = source target_pref.parent.mkdir(parents=True, exist_ok=True) target_pref.write_text(json.dumps(target, ensure_ascii=False, separators=(",", ":")), encoding="utf-8") @@ -746,6 +776,9 @@ ensure_runtime_dirs_owned_by_live() { backup_config \ .pm2 \ .process_runner \ + web-console/out \ + web-console/.next \ + web-console/node_modules \ services/neko/data do path="$ROOT_DIR/$rel" @@ -1318,7 +1351,7 @@ install_neko_browser() { export NEKO_IMAGE="$(resolve_neko_image)" export NEKO_BROWSER_SUPERVISOR_CONF="$(resolve_neko_supervisor_conf)" export NEKO_MANAGED_POLICIES="${NEKO_MANAGED_POLICIES:-0}" - export NEKO_DESKTOP_SCREEN="${NEKO_DESKTOP_SCREEN:-1920x1080@30}" + export NEKO_DESKTOP_SCREEN="${NEKO_DESKTOP_SCREEN:-1280x720@15}" export NEKO_WEBRTC_UDP_RANGE="${NEKO_WEBRTC_UDP_RANGE:-52000-52099}" export NEKO_WEBRTC_UDP_RANGE_1="${NEKO_WEBRTC_UDP_RANGE_1:-$NEKO_WEBRTC_UDP_RANGE}" export NEKO_WEBRTC_UDP_RANGE_2="${NEKO_WEBRTC_UDP_RANGE_2:-52101-52199}" diff --git a/d2ypp2/scripts/linux/service_ctl.sh b/d2ypp2/scripts/linux/service_ctl.sh index 8275c0a..b06300b 100755 --- a/d2ypp2/scripts/linux/service_ctl.sh +++ b/d2ypp2/scripts/linux/service_ctl.sh @@ -314,8 +314,22 @@ neko_managed_policies_enabled() { esac } +copy_neko_tampermonkey_seed_dir() { + local src="${1:-}" dst="${2:-}" marker="${3:-}" + [ -e "$src" ] || return 0 + if [ -e "$dst" ]; then + if [ -z "$marker" ] || grep -R -a -q "$marker" "$dst" 2>/dev/null; then + return 0 + fi + rm -rf "$dst" 2>/dev/null || true + fi + mkdir -p "$(dirname "$dst")" + cp -a "$src" "$dst" 2>/dev/null || true + rm -f "$dst/LOCK" 2>/dev/null || true +} + seed_neko_tampermonkey_profile() { - local target="${1:-}" donor="${2:-}" rel src dst + local target="${1:-}" donor="${2:-}" rel src dst marker [ -n "$target" ] || return 0 if [ -z "$donor" ] || [ ! -d "$donor/Default/Extensions/dhdgffkkebhmkfjojejmpbldmpobfkfo" ]; then donor="$(find_neko_tampermonkey_seed_profile "$target")" @@ -328,21 +342,17 @@ seed_neko_tampermonkey_profile() { "Local Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo"; do src="$donor/Default/$rel" dst="$target/Default/$rel" - [ -e "$src" ] || continue - [ ! -e "$dst" ] || continue - mkdir -p "$(dirname "$dst")" - cp -a "$src" "$dst" 2>/dev/null || true - rm -f "$dst/LOCK" 2>/dev/null || true + marker="Tampermonkey" + case "$rel" in + "Local Extension Settings/"*) marker="YouTube Studio Auto Dismiss" ;; + esac + copy_neko_tampermonkey_seed_dir "$src" "$dst" "$marker" done rel="Managed Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo" src="$donor/Default/$rel" dst="$target/Default/$rel" if neko_managed_policies_enabled; then - if [ -e "$src" ] && [ ! -e "$dst" ]; then - mkdir -p "$(dirname "$dst")" - cp -a "$src" "$dst" 2>/dev/null || true - rm -f "$dst/LOCK" 2>/dev/null || true - fi + copy_neko_tampermonkey_seed_dir "$src" "$dst" "YouTube Studio Auto Dismiss" else rm -rf "$dst" 2>/dev/null || true fi @@ -399,7 +409,22 @@ if not isinstance(source, dict): raise SystemExit(0) target = load(target_pref) settings = target.setdefault("extensions", {}).setdefault("settings", {}) -if ext_id not in settings: + +def should_replace_current(value: object) -> bool: + if not isinstance(value, dict): + return True + if value.get("state") != 1: + return True + if value.get("from_webstore") is not True: + return True + path = str(value.get("path") or "") + if path.startswith("/"): + return True + if value.get("location") == 8: + return True + return False + +if should_replace_current(settings.get(ext_id)): settings[ext_id] = source target_pref.parent.mkdir(parents=True, exist_ok=True) target_pref.write_text(json.dumps(target, ensure_ascii=False, separators=(",", ":")), encoding="utf-8") diff --git a/d2ypp2/services/neko/browser-launch.sh b/d2ypp2/services/neko/browser-launch.sh index f0aea79..a5dfbc7 100755 --- a/d2ypp2/services/neko/browser-launch.sh +++ b/d2ypp2/services/neko/browser-launch.sh @@ -62,33 +62,6 @@ managed_policies_enabled() { esac } -find_tampermonkey_extension_dir() { - seed_dir="${NEKO_TAMPERMONKEY_SEED_DIR:-/etc/neko/tampermonkey-seed}" - ext_id="dhdgffkkebhmkfjojejmpbldmpobfkfo" - for manifest in "$seed_dir/Default/Extensions/$ext_id"/*/manifest.json; do - [ -f "$manifest" ] || continue - dirname "$manifest" - return 0 - done -} - -append_extension_dir() { - extension_dir="${1:-}" - [ -n "$extension_dir" ] || return 0 - [ -d "$extension_dir" ] || return 0 - if [ -n "$load_extension_dirs" ]; then - load_extension_dirs="${load_extension_dirs},${extension_dir}" - else - load_extension_dirs="$extension_dir" - fi -} - -find_youtube_auto_dismiss_extension_dir() { - extension_dir="${NEKO_YOUTUBE_AUTO_DISMISS_EXTENSION_DIR:-/etc/neko/youtube-auto-dismiss-extension}" - [ -f "$extension_dir/manifest.json" ] || return 0 - printf '%s' "$extension_dir" -} - copy_seed_dir_if_missing() { src="${1:-}" dst="${2:-}" @@ -133,7 +106,22 @@ if not isinstance(source, dict): target = load(target_preferences) settings = target.setdefault("extensions", {}).setdefault("settings", {}) current = settings.get(ext_id) -if not isinstance(current, dict) or current.get("state") != 1: + +def should_replace_current(value: object) -> bool: + if not isinstance(value, dict): + return True + if value.get("state") != 1: + return True + if value.get("from_webstore") is not True: + return True + path = str(value.get("path") or "") + if path.startswith("/"): + return True + if value.get("location") == 8: + return True + return False + +if should_replace_current(current): settings[ext_id] = source target_preferences.parent.mkdir(parents=True, exist_ok=True) target_preferences.write_text(json.dumps(target, ensure_ascii=False, separators=(",", ":")), encoding="utf-8") @@ -181,15 +169,6 @@ profile_dir="/home/neko/.config/chromium" if [ "$family" = "google-chrome" ]; then profile_dir="/home/neko/.config/google-chrome" fi -tampermonkey_extension_dir="$(find_tampermonkey_extension_dir || true)" -youtube_auto_dismiss_extension_dir="$(find_youtube_auto_dismiss_extension_dir || true)" -load_extension_dirs="" -append_extension_dir "$tampermonkey_extension_dir" -append_extension_dir "$youtube_auto_dismiss_extension_dir" -load_extension_flags="" -if [ -n "$load_extension_dirs" ]; then - load_extension_flags="--load-extension=$load_extension_dirs" -fi render_mode="${NEKO_BROWSER_RENDER_MODE:-auto}" render_flags="--disable-gpu --use-gl=swiftshader --enable-unsafe-swiftshader" @@ -244,7 +223,6 @@ launch_browser() { --remote-debugging-address=127.0.0.1 \ --remote-debugging-port=9222 \ --user-data-dir="$profile_dir" \ - ${load_extension_flags} \ --password-store=basic \ --no-first-run \ --new-window \ diff --git a/d2ypp2/services/neko/docker-compose.yml b/d2ypp2/services/neko/docker-compose.yml index 410b926..66b621b 100644 --- a/d2ypp2/services/neko/docker-compose.yml +++ b/d2ypp2/services/neko/docker-compose.yml @@ -46,7 +46,6 @@ services: - "./external-extensions:/usr/share/chromium/extensions:ro" - "./external-extensions:/usr/share/chromium-browser/extensions:ro" - "./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro" - - "./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro" - "./provisioning:/var/www/provisioning:ro" - "./browser-launch.sh:/etc/neko/browser-launch.sh:ro" - "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro" @@ -74,7 +73,6 @@ services: - "./external-extensions:/usr/share/chromium/extensions:ro" - "./external-extensions:/usr/share/chromium-browser/extensions:ro" - "./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro" - - "./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro" - "./provisioning:/var/www/provisioning:ro" - "./browser-launch.sh:/etc/neko/browser-launch.sh:ro" - "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro" @@ -102,7 +100,6 @@ services: - "./external-extensions:/usr/share/chromium/extensions:ro" - "./external-extensions:/usr/share/chromium-browser/extensions:ro" - "./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro" - - "./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro" - "./provisioning:/var/www/provisioning:ro" - "./browser-launch.sh:/etc/neko/browser-launch.sh:ro" - "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro" diff --git a/d2ypp2/services/neko/youtube-auto-dismiss-extension/manifest.json b/d2ypp2/services/neko/youtube-auto-dismiss-extension/manifest.json deleted file mode 100644 index 04f108e..0000000 --- a/d2ypp2/services/neko/youtube-auto-dismiss-extension/manifest.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "manifest_version": 3, - "name": "YouTube Studio Auto Dismiss", - "version": "1.1.0", - "description": "Auto-clicks visible Dismiss buttons on YouTube Studio livestreaming pages.", - "content_scripts": [ - { - "matches": [ - "https://studio.youtube.com/channel/*/livestreaming", - "https://studio.youtube.com/video/*/livestreaming", - "https://studio.youtube.com/*/livestreaming" - ], - "js": ["youtube-studio-auto-dismiss.js"], - "run_at": "document_idle" - } - ] -} diff --git a/d2ypp2/services/neko/youtube-auto-dismiss-extension/youtube-studio-auto-dismiss.js b/d2ypp2/services/neko/youtube-auto-dismiss-extension/youtube-studio-auto-dismiss.js deleted file mode 100644 index 76e1f54..0000000 --- a/d2ypp2/services/neko/youtube-auto-dismiss-extension/youtube-studio-auto-dismiss.js +++ /dev/null @@ -1,46 +0,0 @@ -(function () { - "use strict"; - - function isVisible(element) { - var style = window.getComputedStyle(element); - return style.display !== "none" && style.visibility !== "hidden" && element.offsetParent !== null; - } - - function clickElement(element) { - if (!element) return; - element.dispatchEvent( - new MouseEvent("click", { - view: window, - bubbles: true, - cancelable: true, - }) - ); - } - - function findDismiss(root) { - var buttons = (root || document).querySelectorAll("button"); - for (var i = 0; i < buttons.length; i += 1) { - var button = buttons[i]; - var text = button.innerText ? button.innerText.trim() : ""; - if (text === "Dismiss" && isVisible(button)) { - return button; - } - if (button.shadowRoot) { - var shadowButton = findDismiss(button.shadowRoot); - if (shadowButton) return shadowButton; - } - } - return null; - } - - function run() { - clickElement(findDismiss(document)); - } - - if (document.readyState === "complete") { - run(); - } else { - window.addEventListener("load", run, { once: true }); - } - window.setInterval(run, 5000); -})(); diff --git a/d2ypp2/src/hub_kv_store.py b/d2ypp2/src/hub_kv_store.py index f0a613b..d0f7486 100644 --- a/d2ypp2/src/hub_kv_store.py +++ b/d2ypp2/src/hub_kv_store.py @@ -43,7 +43,12 @@ def get_youtube_pro_channels() -> list[dict[str, Any]]: data = json.loads(row[0]) except json.JSONDecodeError: return [] - return data if isinstance(data, list) else [] + if not isinstance(data, list): + return [] + try: + return normalize_youtube_pro_channels(data) + except ValueError: + return [] def set_youtube_pro_channels(channels: list[dict[str, Any]]) -> None: diff --git a/d2ypp2/src/youtube_pro_runtime.py b/d2ypp2/src/youtube_pro_runtime.py index ebb7da8..1ab776f 100644 --- a/d2ypp2/src/youtube_pro_runtime.py +++ b/d2ypp2/src/youtube_pro_runtime.py @@ -10,7 +10,8 @@ _SAFE_PM2_SEGMENT = re.compile(r"[^a-zA-Z0-9_.-]+") _YOUTUBE_HEADER = re.compile(r"^\s*\[youtube\]\s*$", re.IGNORECASE) _ANY_HEADER = re.compile(r"^\s*\[[^\]]+\]\s*$") _KEY_LINE = re.compile(r"^\s*(?:key|stream_key)\s*=", re.IGNORECASE) -_RESERVED_PM2_NAMES = frozenset({"tiktok", "obs", "web"}) +_YOUTUBE_PRO_PM2_PREFIX = "youtube2__" +_RESERVED_PM2_NAMES = frozenset({"youtube", "douyin_youtube", "tiktok", "obs", "web"}) _DEFAULT_YOUTUBE_TEMPLATE = "[youtube]\nkey = \nrtmps = 是\nfast_audio = 0\n" @@ -20,14 +21,23 @@ def sanitize_pm2_segment(value: str) -> str: def default_youtube_pro_pm2_name(channel_id: str) -> str: safe = sanitize_pm2_segment(channel_id) - return f"youtube2__{safe or 'channel'}" + return f"{_YOUTUBE_PRO_PM2_PREFIX}{safe or 'channel'}" + + +def normalize_youtube_pro_pm2_name(raw_value: str, channel_id: str) -> str: + raw = sanitize_pm2_segment(raw_value) + if not raw or raw in _RESERVED_PM2_NAMES or raw == _YOUTUBE_PRO_PM2_PREFIX: + return default_youtube_pro_pm2_name(channel_id) + if raw.startswith(_YOUTUBE_PRO_PM2_PREFIX): + return raw + return default_youtube_pro_pm2_name(raw) def channel_pm2_name(channel: dict[str, Any]) -> str: - raw = sanitize_pm2_segment(str(channel.get("pm2Name", "")).strip()) - if raw: - return raw - return default_youtube_pro_pm2_name(str(channel.get("id", "")).strip()) + return normalize_youtube_pro_pm2_name( + str(channel.get("pm2Name", "")).strip(), + str(channel.get("id", "")).strip(), + ) def managed_url_config_relpath_for_pm2(pm2: str) -> str: diff --git a/d2ypp2/tests/test_neko_config.py b/d2ypp2/tests/test_neko_config.py index a4b9204..29f273f 100644 --- a/d2ypp2/tests/test_neko_config.py +++ b/d2ypp2/tests/test_neko_config.py @@ -4,6 +4,7 @@ import base64 import importlib.util import json import os +import subprocess import tempfile import unittest from pathlib import Path @@ -87,7 +88,6 @@ class NekoConfigTests(unittest.TestCase): self.assertIn("./external-extensions:/usr/share/chromium/extensions:ro", compose) self.assertIn("./external-extensions:/usr/share/chromium-browser/extensions:ro", compose) self.assertIn("./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro", compose) - self.assertIn("./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro", compose) self.assertNotIn("./policies:/etc/chromium/policies/managed", compose) self.assertNotIn("./policies:/etc/opt/chrome/policies/managed", compose) self.assertIn("container_name: live-neko-1", compose) @@ -114,6 +114,11 @@ class NekoConfigTests(unittest.TestCase): { "NEKO_IMAGE": "test-image", "NEKO_PROFILE_HOST_DIR": f"{tmp}/profile", + "NEKO_HTTP_PORT_4": "9404", + "NEKO_WEBRTC_TCPMUX_4": "54304", + "NEKO_WEBRTC_UDPMUX_4": "54305", + "NEKO_WEBRTC_UDP_RANGE_4": "54400-54499", + "NEKO_PROFILE_HOST_DIR_4": f"{tmp}/custom-profile-4", "NEKO_BROWSER_SUPERVISOR_CONF": "google-chrome.conf", }, clear=False, @@ -121,10 +126,11 @@ class NekoConfigTests(unittest.TestCase): rendered = module.render(4) self.assertIn("container_name: live-neko-4", rendered) - self.assertIn('"9203:8080"', rendered) - self.assertIn('"52303:52303/tcp"', rendered) - self.assertIn('"52400-52499:52400-52499/udp"', rendered) - self.assertIn(f'"{tmp}/profile-4:/home/neko/.config/google-chrome"', rendered) + self.assertIn('"9404:8080"', rendered) + self.assertIn('"54304:54304/tcp"', rendered) + self.assertIn('"54305:54305/udp"', rendered) + self.assertIn('"54400-54499:54400-54499/udp"', rendered) + self.assertIn(f'"{tmp}/custom-profile-4:/home/neko/.config/google-chrome"', rendered) self.assertIn('NEKO_MANAGED_POLICIES: "0"', rendered) self.assertIn('"./no-managed-policies:/etc/chromium/policies/managed:ro"', rendered) self.assertIn('"./no-managed-policies:/etc/chromium-browser/policies/managed:ro"', rendered) @@ -133,7 +139,6 @@ class NekoConfigTests(unittest.TestCase): self.assertIn('"./external-extensions:/usr/share/chromium/extensions:ro"', rendered) self.assertIn('"./external-extensions:/usr/share/chromium-browser/extensions:ro"', rendered) self.assertIn('"./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro"', rendered) - self.assertIn('"./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro"', rendered) self.assertNotIn('"./policies:/etc/chromium/policies/managed:ro"', rendered) self.assertNotIn('"./policies:/etc/opt/chrome/policies/managed:ro"', rendered) @@ -153,9 +158,14 @@ class NekoConfigTests(unittest.TestCase): self.assertIn("compose_file=\"$(render_neko_compose_file)\"", script) self.assertIn("NEKO_MAX_INSTANCE_COUNT:-64", script) self.assertIn("NEKO_MANAGED_POLICIES", script) + self.assertIn("copy_neko_tampermonkey_seed_dir()", script) self.assertIn("find_neko_tampermonkey_seed_profile()", script) self.assertIn("services/neko/tampermonkey-seed", script) self.assertIn("sync_neko_tampermonkey_preferences()", script) + self.assertIn("should_replace_current", script) + self.assertIn('value.get("from_webstore") is not True', script) + self.assertIn('path.startswith("/")', script) + self.assertIn('value.get("location") == 8', script) self.assertIn("neko_managed_policies_enabled()", script) def test_tampermonkey_external_extension_seed_is_available_without_managed_policy(self) -> None: @@ -188,17 +198,14 @@ class NekoConfigTests(unittest.TestCase): launch = (ROOT / "services" / "neko" / "browser-launch.sh").read_text(encoding="utf-8") self.assertIn("ensure_tampermonkey_seed", launch) self.assertIn("sync_tampermonkey_preferences", launch) - self.assertIn("find_tampermonkey_extension_dir", launch) - self.assertIn("find_youtube_auto_dismiss_extension_dir", launch) - self.assertIn("--load-extension=$load_extension_dirs", launch) + self.assertIn("should_replace_current", launch) + self.assertIn('value.get("from_webstore") is not True', launch) + self.assertIn('path.startswith("/")', launch) + self.assertIn('value.get("location") == 8', launch) + self.assertNotIn("--load-extension=", launch) + self.assertNotIn("youtube-auto-dismiss-extension", launch) self.assertIn("/etc/neko/tampermonkey-seed", launch) self.assertIn("rm -rf \"$profile_dir/Default/Managed Extension Settings/$ext_id\"", launch) - dismiss_manifest = ROOT / "services" / "neko" / "youtube-auto-dismiss-extension" / "manifest.json" - self.assertTrue(dismiss_manifest.is_file()) - dismiss_script = (ROOT / "services" / "neko" / "youtube-auto-dismiss-extension" / "youtube-studio-auto-dismiss.js").read_text( - encoding="utf-8" - ) - self.assertIn('text === "Dismiss"', dismiss_script) def test_supervisor_uses_browser_launch_script(self) -> None: chrome = (ROOT / "services" / "neko" / "google-chrome.conf").read_text(encoding="utf-8") @@ -251,6 +258,46 @@ class NekoConfigTests(unittest.TestCase): self.assertIn("Local Extension Settings/dhdgffkkebhmkfjojejmpbldmpobfkfo", common) self.assertIn("NEKO_HTTP_PORT_2", common) self.assertIn("NEKO_WEBRTC_UDP_RANGE_3", common) + self.assertIn('eval "override=\\"\\${NEKO_PROFILE_HOST_DIR_${idx}:-}\\""', common) + + def test_neko_common_profile_helper_honors_instance_override_beyond_three(self) -> None: + script = ( + f"ROOT_DIR={ROOT!s}; " + f"source {ROOT / 'scripts' / 'linux' / 'lib' / 'common.sh'}; " + "NEKO_PROFILE_HOST_DIR=/var/lib/live-neko/profile; " + "NEKO_PROFILE_HOST_DIR_4=/srv/live/neko/channel-four; " + "resolve_neko_profile_dir_for_instance 4" + ) + proc = subprocess.run(["bash", "-lc", script], capture_output=True, text=True, check=False) + self.assertEqual(proc.returncode, 0, proc.stderr) + self.assertEqual(proc.stdout.strip(), "/srv/live/neko/channel-four") + + def test_neko_common_arch_selection_covers_x86_and_arm(self) -> None: + script = ( + f"ROOT_DIR={ROOT!s}; " + f"source {ROOT / 'scripts' / 'linux' / 'lib' / 'common.sh'}; " + "NEKO_IMAGE_X86=ghcr.io/m1k1o/neko/google-chrome:3.0.0; " + "NEKO_IMAGE_ARM64=ghcr.io/m1k1o/neko/chromium:3.0.0; " + "uname(){ printf '%s\\n' \"$FAKE_UNAME\"; }; " + "FAKE_UNAME=x86_64; resolve_neko_image; printf ' '; resolve_neko_supervisor_conf; printf '\\n'; " + "FAKE_UNAME=aarch64; resolve_neko_image; printf ' '; resolve_neko_supervisor_conf; printf '\\n'" + ) + proc = subprocess.run(["bash", "-lc", script], capture_output=True, text=True, check=False) + self.assertEqual(proc.returncode, 0, proc.stderr) + self.assertEqual( + proc.stdout.splitlines(), + [ + "ghcr.io/m1k1o/neko/google-chrome:3.0.0 google-chrome.conf", + "ghcr.io/m1k1o/neko/chromium:3.0.0 chromium.conf", + ], + ) + + def test_neko_install_defaults_match_runtime_screen_profile(self) -> None: + common = (ROOT / "scripts" / "linux" / "lib" / "common.sh").read_text(encoding="utf-8") + service_ctl = (ROOT / "scripts" / "linux" / "service_ctl.sh").read_text(encoding="utf-8") + self.assertIn('NEKO_DESKTOP_SCREEN="${NEKO_DESKTOP_SCREEN:-1280x720@15}"', common) + self.assertIn('NEKO_DESKTOP_SCREEN="${NEKO_DESKTOP_SCREEN:-1280x720@15}"', service_ctl) + self.assertNotIn('NEKO_DESKTOP_SCREEN="${NEKO_DESKTOP_SCREEN:-1920x1080@30}"', common) def test_neko_ip_watcher_is_installed_and_restarts_on_drift(self) -> None: common = (ROOT / "scripts" / "linux" / "lib" / "common.sh").read_text(encoding="utf-8") diff --git a/d2ypp2/tests/test_verify_local_install.py b/d2ypp2/tests/test_verify_local_install.py index 9f912c1..002f6a6 100644 --- a/d2ypp2/tests/test_verify_local_install.py +++ b/d2ypp2/tests/test_verify_local_install.py @@ -89,12 +89,22 @@ class VerifyLocalInstallTests(unittest.TestCase): def fake_docker_exec(container: str, command: str, *, timeout: float = 8.0): if "supervisorctl status google-chrome" in command: return 0, "google-chrome RUNNING pid 8", "" + if "NEKO member env invalid" in command: + return 0, "provider=multiuser admin_password=set user_password=set\n", "" + if "/proc/self/mountinfo" in command: + return 0, "/home/neko/.config/chromium\n/home/neko/.config/google-chrome\n", "" + if "Developer mode preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default/Preferences: developer_mode=true\n", "" if "policies/managed" in command and "-name '*.json'" in command: return 0, "", "" if "supervisorctl status tampermonkey-provisioning" in command: return 0, "tampermonkey-provisioning RUNNING pid 9", "" if "tampermonkey-provisioning.json" in command: return 0, "", "" + if "Tampermonkey preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default: state=1 disable_reasons=None\n", "" + if "no standalone youtube extension" in command: + return 0, "no standalone youtube extension\n", "" if "grep -R -a -l" in command: return 0, "/home/neko/.config/google-chrome/Default/Local Extension Settings", "" self.fail(f"unexpected docker exec: {container} {command}") @@ -128,8 +138,12 @@ class VerifyLocalInstallTests(unittest.TestCase): "neko_ip_watch_service", "youtube_pro_neko_capacity", "neko_1_browser", + "neko_1_multiuser_admin", + "neko_1_persistent_profile", + "neko_1_developer_mode", "neko_1_personal_policy_mode", "neko_1_tm_payload", + "neko_1_tm_enabled", "neko_1_tm_storage", "android_devices", "android_screenshot", @@ -143,12 +157,22 @@ class VerifyLocalInstallTests(unittest.TestCase): def fake_docker_exec(container: str, command: str, *, timeout: float = 8.0): if "supervisorctl status google-chrome" in command: return 0, "google-chrome RUNNING pid 8", "" + if "NEKO member env invalid" in command: + return 0, "provider=multiuser admin_password=set user_password=set\n", "" + if "/proc/self/mountinfo" in command: + return 0, "/home/neko/.config/chromium\n/home/neko/.config/google-chrome\n", "" + if "Developer mode preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default/Preferences: developer_mode=true\n", "" if "policies/managed" in command and "-name '*.json'" in command: return 0, "/etc/opt/chrome/policies/managed/policies.json\n", "" if "supervisorctl status tampermonkey-provisioning" in command: return 0, "tampermonkey-provisioning RUNNING pid 9", "" if "tampermonkey-provisioning.json" in command: return 0, "", "" + if "Tampermonkey preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default: state=1 disable_reasons=None\n", "" + if "no standalone youtube extension" in command: + return 0, "no standalone youtube extension\n", "" if "grep -R -a -l" in command: return 1, "", "" self.fail(f"unexpected docker exec: {container} {command}") @@ -174,12 +198,22 @@ class VerifyLocalInstallTests(unittest.TestCase): def fake_docker_exec(container: str, command: str, *, timeout: float = 8.0): if "supervisorctl status google-chrome" in command: return 0, "google-chrome RUNNING pid 8", "" + if "NEKO member env invalid" in command: + return 0, "provider=multiuser admin_password=set user_password=set\n", "" + if "/proc/self/mountinfo" in command: + return 0, "/home/neko/.config/chromium\n/home/neko/.config/google-chrome\n", "" + if "Developer mode preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default/Preferences: developer_mode=true\n", "" if "policies/managed" in command and "-name '*.json'" in command: return 0, "/etc/opt/chrome/policies/managed/policies.json\n", "" if "supervisorctl status tampermonkey-provisioning" in command: return 0, "tampermonkey-provisioning RUNNING pid 9", "" if "tampermonkey-provisioning.json" in command: return 0, "", "" + if "Tampermonkey preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default: state=1 disable_reasons=None\n", "" + if "no standalone youtube extension" in command: + return 0, "no standalone youtube extension\n", "" if "grep -R -a -l" in command: return 1, "", "" self.fail(f"unexpected docker exec: {container} {command}") @@ -197,6 +231,51 @@ class VerifyLocalInstallTests(unittest.TestCase): self.assertFalse(report["ready"]) self.assertEqual(report["failing_checks"][0]["id"], "neko_1_tm_storage") + def test_neko_tampermonkey_enabled_rejects_unpacked_profile_state(self) -> None: + checks: list[dict[str, object]] = [] + + def fake_docker_exec(container: str, command: str, *, timeout: float = 8.0): + if "supervisorctl status google-chrome" in command: + return 0, "google-chrome RUNNING pid 8", "" + if "NEKO member env invalid" in command: + return 0, "provider=multiuser admin_password=set user_password=set\n", "" + if "/proc/self/mountinfo" in command: + return 0, "/home/neko/.config/chromium\n/home/neko/.config/google-chrome\n", "" + if "Developer mode preference not found" in command: + return 0, "/home/neko/.config/google-chrome/Default/Preferences: developer_mode=true\n", "" + if "policies/managed" in command and "-name '*.json'" in command: + return 0, "", "" + if "supervisorctl status tampermonkey-provisioning" in command: + return 0, "tampermonkey-provisioning RUNNING pid 9", "" + if "tampermonkey-provisioning.json" in command: + return 0, "", "" + if "Tampermonkey preference not found" in command: + return ( + 1, + "/home/neko/.config/google-chrome/Default: " + "state=1 disable_reasons=None from_webstore=False " + "location=8 path=/etc/neko/tampermonkey-seed/Default/Extensions/dhdgffkkebhmkfjojejmpbldmpobfkfo/5.5.0_0\n", + "", + ) + if "no standalone youtube extension" in command: + return 0, "no standalone youtube extension\n", "" + if "grep -R -a -l" in command: + return 0, "/home/neko/.config/google-chrome/Default/Local Extension Settings", "" + self.fail(f"unexpected docker exec: {container} {command}") + + with patch.object(verify_local_install, "docker_ps_names", return_value=(True, ["live-neko-1", "live-neko-2"], "")): + with patch.object(verify_local_install, "systemd_active", return_value=(True, "active")): + with patch.object(verify_local_install, "docker_exec", side_effect=fake_docker_exec): + verify_local_install.verify_neko( + checks, + {"ENABLE_NEKO": "1", "NEKO_INSTANCE_COUNT": "2", "NEKO_MANAGED_POLICIES": "0"}, + timeout=5.0, + ) + + report = verify_local_install.summarize(checks) + self.assertFalse(report["ready"]) + self.assertEqual(report["failing_checks"][0]["id"], "neko_1_tm_enabled") + def test_android_endpoint_without_devices_is_not_a_required_install_failure(self) -> None: checks: list[dict[str, object]] = [] with patch.object( diff --git a/d2ypp2/tests/test_web_dynamic_processes.py b/d2ypp2/tests/test_web_dynamic_processes.py index b165773..b381eb9 100644 --- a/d2ypp2/tests/test_web_dynamic_processes.py +++ b/d2ypp2/tests/test_web_dynamic_processes.py @@ -43,17 +43,19 @@ class WebDynamicProcessesTests(unittest.TestCase): def test_script_for_pm2_or_pro_accepts_custom_saved_pm2_name(self) -> None: channels = [{"id": "lane3", "name": "Lane 3", "pm2Name": "custom-lane-three"}] with patch("web.get_youtube_pro_channels", return_value=channels): - resolved = web.script_for_pm2_or_pro("custom-lane-three") + resolved = web.script_for_pm2_or_pro("youtube2__custom-lane-three") self.assertEqual(resolved, "youtube.py") - def test_process_monitor_entries_keep_static_youtube_label_for_lane_one(self) -> None: + def test_process_monitor_entries_migrates_legacy_youtube_pm2_without_hiding_single_lane(self) -> None: channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube"}] with patch("web.get_youtube_pro_channels", return_value=channels): entries = web.process_monitor_entries() youtube_row = next(row for row in entries if row["pm2"] == "youtube") self.assertEqual(youtube_row["label"], "YouTube") + pro_row = next(row for row in entries if row["pm2"] == "youtube2__lane1") + self.assertEqual(pro_row["label"], "YouTube Pro · Lane 1") def test_process_monitor_entries_do_not_duplicate_static_pm2_rows(self) -> None: channels = [ @@ -64,6 +66,7 @@ class WebDynamicProcessesTests(unittest.TestCase): entries = web.process_monitor_entries() self.assertEqual(sum(1 for row in entries if row["pm2"] == "youtube"), 1) + self.assertEqual(sum(1 for row in entries if row["pm2"] == "youtube2__lane1"), 1) self.assertEqual(sum(1 for row in entries if row["pm2"] == "youtube2__lane2"), 1) def test_web_module_does_not_repeat_process_entry_function_defs(self) -> None: @@ -183,6 +186,44 @@ class WebDynamicProcessesTests(unittest.TestCase): self.assertEqual(payload.headers.get("cache-control"), "no-store, max-age=0, must-revalidate") def test_save_url_config_updates_matching_youtube_pro_channel_store(self) -> None: + captured: list[list[dict[str, object]]] = [] + channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube2__lane1", "urlLines": "old\n"}] + + with patch("web.allows_url_config", return_value=True): + with patch("web.managed_url_config_relpath", return_value="URL_config.youtube2__lane1.ini"): + with patch("web.governed_save_managed_file"): + with patch("web.get_youtube_pro_channels", return_value=channels): + with patch("web.set_youtube_pro_channels", side_effect=lambda rows: captured.append(rows)): + payload = asyncio.run( + web.save_url_config( + _JsonRequest({"content": "https://live.douyin.com/fresh\n"}), + process="youtube2__lane1", + ) + ) + + self.assertEqual(_json_body(payload)["message"], "配置保存成功") + self.assertEqual(captured[-1][0]["urlLines"], "https://live.douyin.com/fresh\n") + + def test_save_config_updates_matching_youtube_pro_channel_stream_key(self) -> None: + captured: list[list[dict[str, object]]] = [] + channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube2__lane1", "streamKey": "old-key"}] + content = "[youtube]\nkey = new-key-123\nrtmps = 是\n" + + with patch("web.managed_youtube_ini_relpath", return_value="youtube.youtube2__lane1.ini"): + with patch("web.governed_save_managed_file"): + with patch("web.get_youtube_pro_channels", return_value=channels): + with patch("web.set_youtube_pro_channels", side_effect=lambda rows: captured.append(rows)): + payload = asyncio.run( + web.save_config( + _JsonRequest({"content": content}), + process="youtube2__lane1", + ) + ) + + self.assertEqual(_json_body(payload)["message"], "配置保存成功") + self.assertEqual(captured[-1][0]["streamKey"], "new-key-123") + + def test_single_youtube_save_does_not_mutate_legacy_pro_channel_named_youtube(self) -> None: captured: list[list[dict[str, object]]] = [] channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube", "urlLines": "old\n"}] @@ -193,32 +234,13 @@ class WebDynamicProcessesTests(unittest.TestCase): with patch("web.set_youtube_pro_channels", side_effect=lambda rows: captured.append(rows)): payload = asyncio.run( web.save_url_config( - _JsonRequest({"content": "https://live.douyin.com/fresh\n"}), + _JsonRequest({"content": "https://live.douyin.com/single\n"}), process="youtube", ) ) self.assertEqual(_json_body(payload)["message"], "配置保存成功") - self.assertEqual(captured[-1][0]["urlLines"], "https://live.douyin.com/fresh\n") - - def test_save_config_updates_matching_youtube_pro_channel_stream_key(self) -> None: - captured: list[list[dict[str, object]]] = [] - channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube", "streamKey": "old-key"}] - content = "[youtube]\nkey = new-key-123\nrtmps = 是\n" - - with patch("web.managed_youtube_ini_relpath", return_value="youtube.youtube.ini"): - with patch("web.governed_save_managed_file"): - with patch("web.get_youtube_pro_channels", return_value=channels): - with patch("web.set_youtube_pro_channels", side_effect=lambda rows: captured.append(rows)): - payload = asyncio.run( - web.save_config( - _JsonRequest({"content": content}), - process="youtube", - ) - ) - - self.assertEqual(_json_body(payload)["message"], "配置保存成功") - self.assertEqual(captured[-1][0]["streamKey"], "new-key-123") + self.assertEqual(captured, []) if __name__ == "__main__": diff --git a/d2ypp2/tests/test_youtube_pro_runtime.py b/d2ypp2/tests/test_youtube_pro_runtime.py index 18e085d..4a6a2ae 100644 --- a/d2ypp2/tests/test_youtube_pro_runtime.py +++ b/d2ypp2/tests/test_youtube_pro_runtime.py @@ -17,6 +17,10 @@ class YoutubeProRuntimeTests(unittest.TestCase): def test_normalize_channels_assigns_default_pm2_and_rejects_duplicate_names(self) -> None: rows = normalize_youtube_pro_channels([{"id": "lane2", "name": "Lane 2"}]) self.assertEqual(rows[0]["pm2Name"], "youtube2__lane2") + rows = normalize_youtube_pro_channels([{"id": "lane1", "pm2Name": "youtube"}]) + self.assertEqual(rows[0]["pm2Name"], "youtube2__lane1") + rows = normalize_youtube_pro_channels([{"id": "lane3", "pm2Name": "custom"}]) + self.assertEqual(rows[0]["pm2Name"], "youtube2__custom") with self.assertRaises(ValueError): normalize_youtube_pro_channels( diff --git a/d2ypp2/tools/render_neko_compose.py b/d2ypp2/tools/render_neko_compose.py index 54ad297..d539134 100644 --- a/d2ypp2/tools/render_neko_compose.py +++ b/d2ypp2/tools/render_neko_compose.py @@ -113,7 +113,6 @@ def render(count: int) -> str: ' - "./external-extensions:/usr/share/chromium/extensions:ro"', ' - "./external-extensions:/usr/share/chromium-browser/extensions:ro"', ' - "./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro"', - ' - "./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro"', ' - "./provisioning:/var/www/provisioning:ro"', ' - "./browser-launch.sh:/etc/neko/browser-launch.sh:ro"', f" - {q(f'./{supervisor_conf}:/etc/neko/supervisord/{supervisor_conf}:ro')}", diff --git a/d2ypp2/tools/verify_local_install.py b/d2ypp2/tools/verify_local_install.py index 0b44766..1555f65 100755 --- a/d2ypp2/tools/verify_local_install.py +++ b/d2ypp2/tools/verify_local_install.py @@ -333,6 +333,70 @@ def verify_neko(checks: list[dict[str, Any]], env: dict[str, str], *, timeout: f detail=(out or err2).strip(), hint="Make services/neko/browser-launch.sh executable and restart Neko.", ) + code, out, err2 = docker_exec( + name, + "if [ \"${NEKO_MEMBER_PROVIDER:-}\" = multiuser ] " + "&& [ -n \"${NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD:-}\" ] " + "&& [ -n \"${NEKO_MEMBER_MULTIUSER_USER_PASSWORD:-}\" ]; then " + "printf 'provider=%s admin_password=set user_password=set\\n' \"$NEKO_MEMBER_PROVIDER\"; " + "else echo 'NEKO member env invalid'; exit 1; fi", + timeout=timeout, + ) + check( + checks, + f"neko_{idx}_multiuser_admin", + f"{name} multiuser admin enabled", + code == 0, + detail=(out or err2).strip(), + hint="Neko must run with multiuser provider and a non-empty admin password.", + ) + code, out, err2 = docker_exec( + name, + "awk '$5==\"/home/neko/.config/google-chrome\" || $5==\"/home/neko/.config/chromium\" {print $5}' " + "/proc/self/mountinfo | sort -u", + timeout=timeout, + ) + mounted_profiles = {line.strip() for line in out.splitlines() if line.strip()} + check( + checks, + f"neko_{idx}_persistent_profile", + f"{name} persistent browser profile", + code == 0 + and { + "/home/neko/.config/google-chrome", + "/home/neko/.config/chromium", + }.issubset(mounted_profiles), + detail=out.strip() or err2.strip() or "profile mounts missing", + hint="Neko profile directories must be bind-mounted so Google login, Tampermonkey, and channel state survive restarts.", + ) + code, out, err2 = docker_exec( + name, + "python3 - <<'PY'\n" + "import json\n" + "from pathlib import Path\n" + "for path in (Path('/home/neko/.config/google-chrome/Default/Preferences'), Path('/home/neko/.config/chromium/Default/Preferences'), Path('/home/neko/.config/google-chrome/Local State'), Path('/home/neko/.config/chromium/Local State')):\n" + " if not path.exists():\n" + " continue\n" + " try:\n" + " data = json.loads(path.read_text(encoding='utf-8'))\n" + " except Exception:\n" + " continue\n" + " if data.get('extensions', {}).get('ui', {}).get('developer_mode') is True:\n" + " print(f'{path}: developer_mode=true')\n" + " raise SystemExit(0)\n" + "print('Developer mode preference not found')\n" + "raise SystemExit(1)\n" + "PY", + timeout=timeout, + ) + check( + checks, + f"neko_{idx}_developer_mode", + f"{name} Chrome developer mode", + code == 0, + detail=(out or err2).strip(), + hint="browser-launch.sh must set extensions.ui.developer_mode in Preferences/Local State before Chrome starts.", + ) code, out, err2 = docker_exec( name, "find /etc/chromium/policies/managed /etc/chromium-browser/policies/managed /etc/opt/chrome/policies/managed " @@ -379,22 +443,89 @@ def verify_neko(checks: list[dict[str, Any]], env: dict[str, str], *, timeout: f detail="payload contains YouTube Studio Auto Dismiss" if code == 0 else (err2 or out).strip(), hint="Regenerate services/neko/provisioning/tampermonkey-provisioning.json and restart Neko.", ) + code, out, err2 = docker_exec( + name, + "python3 - <<'PY'\n" + "import json\n" + "from pathlib import Path\n" + "ext = 'dhdgffkkebhmkfjojejmpbldmpobfkfo'\n" + "for base in ('/home/neko/.config/google-chrome/Default', '/home/neko/.config/chromium/Default'):\n" + " path = Path(base) / 'Preferences'\n" + " if not path.exists():\n" + " continue\n" + " try:\n" + " data = json.loads(path.read_text(encoding='utf-8'))\n" + " except Exception:\n" + " continue\n" + " state = data.get('extensions', {}).get('settings', {}).get(ext, {})\n" + " if state:\n" + " path_value = str(state.get('path') or '')\n" + " enabled = (\n" + " state.get('state') == 1\n" + " and not state.get('disable_reasons')\n" + " and state.get('from_webstore') is True\n" + " and not path_value.startswith('/')\n" + " and state.get('location') != 8\n" + " )\n" + " print(\n" + " f\"{base}: state={state.get('state')} disable_reasons={state.get('disable_reasons')} \"\n" + " f\"from_webstore={state.get('from_webstore')} location={state.get('location')} path={path_value}\"\n" + " )\n" + " raise SystemExit(0 if enabled else 1)\n" + "print('Tampermonkey preference not found')\n" + "raise SystemExit(1)\n" + "PY", + timeout=timeout, + ) + check( + checks, + f"neko_{idx}_tm_enabled", + f"{name} Tampermonkey enabled", + code == 0, + detail=(out or err2).strip(), + hint="Tampermonkey must be a normal enabled extension, not an unpacked forced-disabled extension.", + ) + code, out, err2 = docker_exec( + name, + "python3 - <<'PY'\n" + "import os\n" + "skip = {os.getpid(), os.getppid()}\n" + "bad = [b'--load-' + b'extension=', b'youtube-auto-' + b'dismiss-extension']\n" + "for name in os.listdir('/proc'):\n" + " if not name.isdigit() or int(name) in skip:\n" + " continue\n" + " try:\n" + " cmdline = open(f'/proc/{name}/cmdline', 'rb').read()\n" + " except OSError:\n" + " continue\n" + " if any(marker in cmdline for marker in bad):\n" + " print(cmdline.replace(b'\\0', b' ').decode('utf-8', errors='replace'))\n" + " raise SystemExit(1)\n" + "print('no standalone youtube extension')\n" + "PY", + timeout=timeout, + ) + check( + checks, + f"neko_{idx}_no_standalone_youtube_extension", + f"{name} no standalone YouTube extension", + code == 0, + detail=(out or err2).strip(), + hint="The YouTube Studio Auto Dismiss automation must live inside Tampermonkey, not as a separate --load-extension.", + ) code, out, err2 = docker_exec( name, "for base in /home/neko/.config/google-chrome/Default /home/neko/.config/chromium/Default; do " "for area in 'Local Extension Settings' 'Managed Extension Settings'; do " "dir=\"$base/$area/dhdgffkkebhmkfjojejmpbldmpobfkfo\"; " "if [ -d \"$dir\" ] && grep -R -a -l 'YouTube Studio Auto Dismiss' \"$dir\" 2>/dev/null | head -1; then exit 0; fi; " - "done; done; " - "for cmd in /proc/[0-9]*/cmdline; do " - "tr '\\0' '\\n' <\"$cmd\" 2>/dev/null | grep -q -- '--load-extension=.*youtube-auto-dismiss-extension' && echo '--load-extension youtube-auto-dismiss-extension' && exit 0; " - "done; exit 1", + "done; done; exit 1", timeout=timeout, ) check( checks, f"neko_{idx}_tm_storage", - f"{name} Tampermonkey script imported", + f"{name} Tampermonkey YouTube script imported", code == 0 and bool(out.strip()), required=True, detail=out.strip() or err2.strip() or "not found", diff --git a/d2ypp2/web-console/components/live-product/LiveYoutubeUnmannedView.tsx b/d2ypp2/web-console/components/live-product/LiveYoutubeUnmannedView.tsx index ad56ca8..284c64c 100644 --- a/d2ypp2/web-console/components/live-product/LiveYoutubeUnmannedView.tsx +++ b/d2ypp2/web-console/components/live-product/LiveYoutubeUnmannedView.tsx @@ -132,7 +132,7 @@ function resolveChannelPm2(channel: YoutubeProChannel): string { } const MODE_KEY = "live-hub-youtube-mode-v1"; -const PRO_PM2_RESERVED = new Set(["tiktok", "obs", "web"]); +const PRO_PM2_RESERVED = new Set(["youtube", "douyin_youtube", "tiktok", "obs", "web"]); /** UI 暂时隐藏「多频道 Pro」切换(DOM 与逻辑保留,改 false 即可恢复) */ const HIDE_YOUTUBE_MULTI_PRO_TOGGLE = false; @@ -337,7 +337,6 @@ export function LiveYoutubeUnmannedView({ quickLinks, }: Props) { const ytEntries = useMemo(() => entries.filter(isYoutubeProcess), [entries]); - const staticYoutubeEntries = useMemo(() => ytEntries.filter((entry) => isStaticYoutubeControlEntry(entry)), [ytEntries]); const singleProcessOptions = useMemo( () => buildSingleProcessOptions(ytEntries.length ? ytEntries : entries, liveProcesses), [entries, liveProcesses, ytEntries], @@ -713,11 +712,7 @@ export function LiveYoutubeUnmannedView({ if (m === "pro" && channels.length) { const first = channels[0]; const latestSingleUrlDraft = singleUrlDraftRef.current.trim(); - const youtubePm2Ok = staticYoutubeEntries.some((e) => e.pm2 === currentProc); - const pm2Name = - youtubePm2Ok && currentProc.trim() - ? currentProc.trim() - : resolveChannelPm2(first); + const pm2Name = resolveChannelPm2(first); const next: YoutubeProChannel[] = [ { ...first, @@ -744,8 +739,6 @@ export function LiveYoutubeUnmannedView({ channels, applyProUrlDraft, ytFields.key, - currentProc, - staticYoutubeEntries, activeCh, persistChannels, ], diff --git a/d2ypp2/web-console/lib/youtubeProChannels.ts b/d2ypp2/web-console/lib/youtubeProChannels.ts index 2bfedb3..2c01c21 100644 --- a/d2ypp2/web-console/lib/youtubeProChannels.ts +++ b/d2ypp2/web-console/lib/youtubeProChannels.ts @@ -13,15 +13,25 @@ export type YoutubeProChannel = { }; const STORAGE_KEY = "live-hub-youtube-pro-v2"; +const YOUTUBE_PRO_PM2_PREFIX = "youtube2__"; const PM2_SANITIZE_RE = /[^a-zA-Z0-9_.-]+/g; +const RESERVED_PRO_PM2_NAMES = new Set(["youtube", "douyin_youtube", "tiktok", "obs", "web"]); export function sanitizeYoutubePm2Name(value: string): string { return (value || "").trim().replace(PM2_SANITIZE_RE, "_"); } +export function normalizeYoutubeProPm2Name(value: string, channelId: string): string { + const raw = sanitizeYoutubePm2Name(value); + if (!raw || RESERVED_PRO_PM2_NAMES.has(raw) || raw === YOUTUBE_PRO_PM2_PREFIX) { + return defaultPm2NameForChannel(channelId); + } + if (raw.startsWith(YOUTUBE_PRO_PM2_PREFIX)) return raw; + return defaultPm2NameForChannel(raw); +} + export function resolveYoutubeProChannelPm2(channel: Pick): string { - const raw = sanitizeYoutubePm2Name(String(channel.pm2Name || "")); - return raw || defaultPm2NameForChannel(String(channel.id || "")); + return normalizeYoutubeProPm2Name(String(channel.pm2Name || ""), String(channel.id || "")); } export function parseYoutubeProChannelList(raw: unknown): YoutubeProChannel[] { @@ -42,7 +52,7 @@ function migrateRow(x: Record): YoutubeProChannel | null { streamKeySuffix: typeof x.streamKeySuffix === "string" ? x.streamKeySuffix : undefined, streamKey: typeof x.streamKey === "string" ? x.streamKey : undefined, urlLines: typeof x.urlLines === "string" ? x.urlLines : undefined, - pm2Name: typeof x.pm2Name === "string" ? x.pm2Name : undefined, + pm2Name: normalizeYoutubeProPm2Name(typeof x.pm2Name === "string" ? x.pm2Name : "", id), notes: typeof x.notes === "string" ? x.notes : undefined, }; } @@ -126,5 +136,5 @@ export function newChannelId(): string { } export function defaultPm2NameForChannel(channelId: string): string { - return `youtube2__${sanitizeYoutubePm2Name(channelId) || "channel"}`; + return `${YOUTUBE_PRO_PM2_PREFIX}${sanitizeYoutubePm2Name(channelId) || "channel"}`; } diff --git a/d2ypp2/web-console/out/.build-stamp.json b/d2ypp2/web-console/out/.build-stamp.json index 8fffbee..f885f59 100644 --- a/d2ypp2/web-console/out/.build-stamp.json +++ b/d2ypp2/web-console/out/.build-stamp.json @@ -1,6 +1,6 @@ { - "built_at": 1779172552.256737, - "source_mtime": 1779162468.269062, + "built_at": 1779182151.9524395, + "source_mtime": 1779180451.7832174, "toolchain": "local", "node_major": 20 } \ No newline at end of file diff --git a/d2ypp2/web-console/out/404.html b/d2ypp2/web-console/out/404.html index 6d5833a..fcdca3c 100644 --- a/d2ypp2/web-console/out/404.html +++ b/d2ypp2/web-console/out/404.html @@ -1 +1 @@ -404: This page could not be found.无人直播系统 · live.local

404

This page could not be found.

\ No newline at end of file +404: This page could not be found.无人直播系统 · live.local

404

This page could not be found.

\ No newline at end of file diff --git a/d2ypp2/web-console/out/_next/static/z_UuUy3mGDwiCWfhwZJVM/_buildManifest.js b/d2ypp2/web-console/out/_next/static/UmN0Ou_Iv2TWI4xcHvY2X/_buildManifest.js similarity index 100% rename from d2ypp2/web-console/out/_next/static/z_UuUy3mGDwiCWfhwZJVM/_buildManifest.js rename to d2ypp2/web-console/out/_next/static/UmN0Ou_Iv2TWI4xcHvY2X/_buildManifest.js diff --git a/d2ypp2/web-console/out/_next/static/z_UuUy3mGDwiCWfhwZJVM/_ssgManifest.js b/d2ypp2/web-console/out/_next/static/UmN0Ou_Iv2TWI4xcHvY2X/_ssgManifest.js similarity index 100% rename from d2ypp2/web-console/out/_next/static/z_UuUy3mGDwiCWfhwZJVM/_ssgManifest.js rename to d2ypp2/web-console/out/_next/static/UmN0Ou_Iv2TWI4xcHvY2X/_ssgManifest.js diff --git a/d2ypp2/web-console/out/_next/static/chunks/app/page-10361036b8bf1ca2.js b/d2ypp2/web-console/out/_next/static/chunks/app/page-10361036b8bf1ca2.js deleted file mode 100644 index 4938bcb..0000000 --- a/d2ypp2/web-console/out/_next/static/chunks/app/page-10361036b8bf1ca2.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{4578:function(e,t,s){Promise.resolve().then(s.bind(s,1499))},1499:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return e8}});var n=s(7437),l=s(6247),i=s(7586),r=s(4401),a=s(6137),o=s(4372),c=s(5901),d=s(3388),x=s(3420),u=s(8728),m=s(2023),h=s(407),p=s(6840),b=s(7226),g=s(5929),f=s(7945),v=s(1817),y=s(7168),w=s(4822),N=s(4428),j=s(1723),k=s(2926),z=s(7580),S=s(2489),_=s(2265);function C(e){let{tr:t}=e,l=(0,_.useRef)(null);return(0,_.useEffect)(()=>{let e;if(!l.current)return;let t=!1,n=0;return s.e(689).then(s.bind(s,1448)).then(s=>{if(t||!l.current)return;let i=l.current,r=Math.max(i.clientWidth,280),a=Math.max(i.clientHeight,200),o=new s.Scene,c=new s.PerspectiveCamera(48,r/a,.1,80);c.position.set(0,1.1,7.2);let d=new s.WebGLRenderer({antialias:!0,alpha:!0});d.setPixelRatio(Math.min(window.devicePixelRatio,2)),d.setSize(r,a),d.setClearColor(0,0),i.appendChild(d.domElement);let x=new s.HemisphereLight(16762092,4482815,.85);o.add(x);let u=new s.DirectionalLight(16777215,.9);u.position.set(4,8,6),o.add(u);let m=new s.PointLight(8189439,.6,20);m.position.set(-3,2,-2),o.add(m);let h=new s.Group,p=new s.Mesh(new s.BoxGeometry(3.2,.35,2.2),new s.MeshStandardMaterial({color:2762048,metalness:.15,roughness:.55}));p.position.y=-.85,h.add(p);let b=new s.Mesh(new s.TorusGeometry(.72,.09,12,48),new s.MeshStandardMaterial({color:16724821,emissive:4456465,metalness:.35,roughness:.25}));b.rotation.x=Math.PI/2,b.position.set(-.85,.15,.2),h.add(b);let g=new s.Mesh(new s.ConeGeometry(.35,.5,3),new s.MeshStandardMaterial({color:16777215,emissive:2236962,metalness:.2,roughness:.3}));g.rotation.z=-Math.PI/2,g.rotation.y=Math.PI,g.position.set(-.55,.18,.2),h.add(g);let f=new s.Mesh(new s.CylinderGeometry(.22,.28,.95,20),new s.MeshStandardMaterial({color:2487534,emissive:340024,metalness:.25,roughness:.35}));f.position.set(1.05,.35,-.15),f.rotation.z=.12,h.add(f);let v=new s.Mesh(new s.SphereGeometry(.26,16,16),new s.MeshStandardMaterial({color:16657493,emissive:2229520,metalness:.2,roughness:.4}));v.position.set(1.05,.92,-.15),h.add(v);let y=new s.BufferGeometry,w=new Float32Array(360);for(let e=0;e<120;e++)w[3*e]=(Math.random()-.5)*14,w[3*e+1]=(Math.random()-.3)*8,w[3*e+2]=(Math.random()-.5)*8-2;y.setAttribute("position",new s.BufferAttribute(w,3));let N=new s.Points(y,new s.PointsMaterial({color:16777215,size:.06,transparent:!0,opacity:.7}));o.add(N),o.add(h);let j=performance.now(),k=()=>{if(t)return;n=requestAnimationFrame(k);let e=(performance.now()-j)/1e3;h.rotation.y=.25*Math.sin(.35*e)+.12*e,h.position.y=.06*Math.sin(.9*e),b.rotation.z=.4*e,N.rotation.y=.02*e,d.render(o,c)};k();let z=new ResizeObserver(()=>{if(!l.current||t)return;let e=Math.max(l.current.clientWidth,280),s=Math.max(l.current.clientHeight,200);c.aspect=e/s,c.updateProjectionMatrix(),d.setSize(e,s)});z.observe(i),e=()=>{cancelAnimationFrame(n),z.disconnect(),d.dispose(),y.dispose(),d.domElement.parentNode===i&&i.removeChild(d.domElement)}}),()=>{t=!0,cancelAnimationFrame(n),null==e||e()}},[]),(0,n.jsxs)("div",{className:"flex h-full min-h-[14rem] flex-col",children:[(0,n.jsx)("p",{className:"mb-2 px-1 text-[10px] font-medium uppercase tracking-wider text-fuchsia-200/80",children:t("直播工作室 \xb7 3D","Live studio \xb7 3D")}),(0,n.jsx)("div",{ref:l,className:"relative min-h-[12rem] flex-1 overflow-hidden rounded-xl bg-gradient-to-b from-fuchsia-950/40 to-cyan-950/20 ring-1 ring-white/10"})]})}var R=s(9170),P=s(2246),L=s(4286),M=s(4794),T=s(221),U=s(8867),E=s(8124),I=s(2101),D=s(3651),A=s(9985),Z=s(6362),O=s(3468),H=s(6443),B=s(5287),K=s(3276),F=s(9227),W=s(257),Y=s(1387);class J{reset(){if(this.buf=new Uint8Array(0),this.sps=null,this.pps=null,this.configured=!1,this.configuring=!1,this.ts=0,this.decoder){try{this.decoder.close()}catch(e){}this.decoder=null}}push(e){let t=new Uint8Array(e.byteLength);t.set(new Uint8Array(e)),this.buf=function(e,t){let s=new Uint8Array(e.length+t.length);return s.set(e,0),s.set(t,e.length),s}(this.buf,t),this.drainAvcc()}drainAvcc(){let e=this.buf,t=0;for(;t+4<=e.length;){var s;let n=e[s=t]<<24|e[s+1]<<16|e[s+2]<<8|e[s+3];if(n<=0||n>6291456){this.buf=new Uint8Array(e.subarray(t+1)),t=0;continue}if(t+4+n>e.length)break;let l=e.subarray(t+4,t+4+n);t+=4+n,this.handleNal(l)}t>0&&(this.buf=new Uint8Array(e.subarray(t)))}handleNal(e){if(e.length<2)return;let t=31&e[0];if(7===t?this.sps=new Uint8Array(e):8===t&&(this.pps=new Uint8Array(e)),this.sps&&this.pps&&!this.configured&&!this.configuring&&this.configure(),!this.configured||!this.decoder||1!==t&&5!==t&&7!==t&&8!==t||7===t||8===t)return;let s=new Uint8Array(4+e.length);new DataView(s.buffer).setUint32(0,e.length,!1),s.set(e,4);try{let e=new EncodedVideoChunk({type:5===t?"key":"delta",timestamp:this.ts,data:s});this.ts+=33333,this.decoder.decode(e)}catch(e){this.onDecodeError(e.message||String(e))}}async configure(){if(this.sps&&this.pps&&!this.configured&&!this.configuring){this.configuring=!0;try{let e=function(e,t){let s=e.subarray(1),n=t.subarray(1),l=new Uint8Array(11+s.length+3+n.length),i=0;return l[i++]=1,l[i++]=e[1],l[i++]=e[2],l[i++]=e[3],l[i++]=255,l[i++]=225,l[i++]=s.length>>8&255,l[i++]=255&s.length,l.set(s,i),i+=s.length,l[i++]=1,l[i++]=n.length>>8&255,l[i++]=255&n.length,l.set(n,i),l}(this.sps,this.pps),t=function(e){let t=e=>e.toString(16).padStart(2,"0").toUpperCase();return"avc1.".concat(t(e[1])).concat(t(e[2])).concat(t(e[3]))}(this.sps),s=new VideoDecoder({output:e=>{var t;let s=this.canvas.getContext("2d");if(!s){e.close();return}(this.canvas.width!==e.displayWidth||this.canvas.height!==e.displayHeight)&&(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),s.drawImage(e,0,0),e.close(),null===(t=this.onFrame)||void 0===t||t.call(this)},error:e=>this.onDecodeError(String(e.message||e))});await s.configure({codec:t,description:e,optimizeForLatency:!0}),this.decoder=s,this.configured=!0}catch(e){this.onDecodeError(e.message||String(e))}finally{this.configuring=!1}}}constructor(e,t,s){this.canvas=e,this.onDecodeError=t,this.onFrame=s,this.buf=new Uint8Array(0),this.decoder=null,this.configured=!1,this.configuring=!1,this.ts=0,this.sps=null,this.pps=null}}function G(){return"undefined"!=typeof VideoDecoder&&"undefined"!=typeof VideoFrame}let V="live-hub-adb-bookmarks-v1";function q(e,t,s){let n,l,i,r;let a=e.getBoundingClientRect(),o=e.width,c=e.height;if(!o||!c)return null;let d=a.width/a.height,x=o/c;x>d?(n=a.width,l=a.width/x,i=0,r=(a.height-l)/2):(l=a.height,n=a.height*x,i=(a.width-n)/2,r=0);let u=t-a.left-i,m=s-a.top-r;return u<0||m<0||u>n||m>l?null:{x:Math.max(0,Math.min(o-1,Math.round(u/n*o))),y:Math.max(0,Math.min(c-1,Math.round(m/l*c)))}}function X(e,t,s){let n,l,i,r;let a=e.getBoundingClientRect(),o=e.naturalWidth,c=e.naturalHeight;if(!o||!c)return null;let d=a.width/a.height,x=o/c;x>d?(n=a.width,l=a.width/x,i=0,r=(a.height-l)/2):(l=a.height,n=a.height*x,i=(a.width-n)/2,r=0);let u=t-a.left-i,m=s-a.top-r;return u<0||m<0||u>n||m>l?null:{x:Math.max(0,Math.min(o-1,Math.round(u/n*o))),y:Math.max(0,Math.min(c-1,Math.round(m/l*c)))}}let $=[0,280,450,700,1100];function Q(e){switch(e){case"usb":return{Icon:I.Z,zh:"USB",en:"USB",cls:"bg-amber-500/20 text-amber-100 ring-amber-500/35"};case"tcp":return{Icon:k.Z,zh:"网络",en:"TCP",cls:"bg-cyan-500/20 text-cyan-100 ring-cyan-500/35"};case"emulator":return{Icon:D.Z,zh:"模拟器",en:"Emu",cls:"bg-fuchsia-500/20 text-fuchsia-100 ring-fuchsia-500/35"};default:return{Icon:d.Z,zh:"?",en:"?",cls:"bg-zinc-600/30 text-zinc-400"}}}let ee="https://github.com/Genymobile/scrcpy",et="https://github.com/viarotel-org/escrcpy";function es(e,t){let s=t.startsWith("/")?t:"/".concat(t),n=(e||"").trim().replace(/\/$/,"");return n?"".concat(n).concat(s):s}function en(e){var t;let{t:s,apiBase:l,fetchJson:i,serial:r,devices:a,setSerial:o,adbAvailable:c,lock:x,overview:u,onAndroidAction:h,notify:p,onRefreshDevices:b}=e,[g,f]=(0,_.useState)(0),[v,w]=(0,_.useState)(450),[N,j]=(0,_.useState)(!1),[k,z]=(0,_.useState)(null),[S,C]=(0,_.useState)(null),[R,P]=(0,_.useState)(!0),[L,M]=(0,_.useState)(""),[T,U]=(0,_.useState)(""),[E,I]=(0,_.useState)("37777"),[D,en]=(0,_.useState)(""),[el,ei]=(0,_.useState)(!1),[er,ea]=(0,_.useState)([]),[eo,ec]=(0,_.useState)(!1),[ed,ex]=(0,_.useState)(null),[eu,em]=(0,_.useState)(!1),[eh,ep]=(0,_.useState)(null),[eb,eg]=(0,_.useState)(null),[ef,ev]=(0,_.useState)(!0),ey=(0,_.useRef)(null),ew=(0,_.useRef)(null),eN=(0,_.useRef)(null),ej=(0,_.useRef)(null),ek=(0,_.useRef)(null),ez=(0,_.useRef)(null),eS=(0,_.useRef)(0),e_=(0,_.useRef)(!1),eC=(0,_.useRef)(null),eR=(0,_.useRef)(!1),eP=null===(t=a.find(e=>e.serial===r))||void 0===t?void 0:t.transport,eL=v>0,eM=r?"".concat(es(l,"/android/screenshot"),"?serial=").concat(encodeURIComponent(r),"&ts=").concat(g).concat(eL?"&fast=1":""):"",eT=(0,_.useCallback)(()=>{f(e=>e+1)},[]),eU=(0,_.useCallback)(()=>{null!=eC.current&&(window.clearTimeout(eC.current),eC.current=null)},[]);(0,_.useEffect)(()=>{let e=()=>ev("visible"===document.visibilityState);return e(),document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[]),(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(V);if(e){let t=JSON.parse(e);Array.isArray(t)&&ea(t.map(String).filter(Boolean).slice(0,24))}}catch(e){}},[]);let eE=e=>{let t=e.trim();if(!t)return;let n=[t,...er.filter(e=>e!==t)].slice(0,16);ea(n);try{window.localStorage.setItem(V,JSON.stringify(n))}catch(e){}p(s("已保存快捷地址","Saved quick address"))};(0,_.useEffect)(()=>{if(!r||!c){C(null);return}let e=!1;return(async()=>{try{let t=await (0,Y.N)("".concat(es(l,"/android/display_metrics"),"?serial=").concat(encodeURIComponent(r)));if(e)return;"number"==typeof t.width&&"number"==typeof t.height&&C({width:t.width,height:t.height})}catch(e){}})(),()=>{e=!0}},[l,c,r]),(0,_.useEffect)(()=>{if(!c||!r||v<=0||eo||!ef)return;let e=window.setInterval(()=>f(e=>e+1),v);return()=>clearInterval(e)},[c,v,ef,r,eo]),(0,_.useEffect)(()=>{ef&&c&&r&&!eo&&eT()},[c,eT,ef,r,eo]),(0,_.useEffect)(()=>{if(!c){eg(null);return}let e=!1;return(async()=>{try{let t=await (0,Y.N)(es(l,"/android/scrcpy/info"));e||eg(t)}catch(e){}})(),()=>{e=!0}},[l,c]),(0,_.useEffect)(()=>{eo||ep(null)},[eo]),(0,_.useEffect)(()=>{ex(null),e_.current=!1},[r]),(0,_.useEffect)(()=>{let e=a.find(e=>e.serial===r),t=!!(r&&ed===r);if(c&&r&&(null==e?void 0:e.state)==="device"&&(null==eb?void 0:eb.server_jar)&&G()&&!t){ec(!0),w(0);return}if(t||!r||!c||eb&&!eb.server_jar||!G()||e&&"device"!==e.state){ec(!1);return}},[r,a,c,eb,ed]),(0,_.useEffect)(()=>{if(!eo||!r||!c){var e,t;eU(),e_.current=!0,eR.current=!1,null===(e=ej.current)||void 0===e||e.close(),ej.current=null,null===(t=ek.current)||void 0===t||t.reset(),ek.current=null,em(!1);return}if(!G()){ep(s("当前浏览器不支持 WebCodecs H.264","WebCodecs H.264 not supported in this browser")),ec(!1);return}let n=eN.current;if(!n)return;let i=e=>{var t;eU(),e_.current=!0,null===(t=ej.current)||void 0===t||t.close(),ep(e),ec(!1),w(450),ex(r),window.setTimeout(()=>eT(),120)},a=new J(n,e=>i("".concat(s("实时画面解码失败,已切回截图模式","Live stream decode failed, using screenshot mode"),": ").concat(e)),()=>{eR.current=!0,eU()});ek.current=a,e_.current=!1,eR.current=!1;let o=new WebSocket(function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1920,n=(function(e){let t=(e||"").trim();if(t)try{let e=new URL(t,window.location.href),s="https:"===e.protocol?"wss:":"ws:";return"".concat(s,"//").concat(e.host)}catch(e){}let s=void 0!==W&&W.env.NEXT_PUBLIC_API_URL?String(W.env.NEXT_PUBLIC_API_URL).trim():"";if(s)try{let e=new URL(s,window.location.href),t="https:"===e.protocol?"wss:":"ws:";return"".concat(t,"//").concat(e.host)}catch(e){}let n=window.location.port;if("3000"===n||"3001"===n){let e=window.location.hostname||"127.0.0.1";return"ws://".concat(e,":").concat("8001")}let{protocol:l,host:i}=window.location;return"".concat("https:"===l?"wss:":"ws:","//").concat(i)})(e).replace(/\/$/,""),l=new URLSearchParams({serial:t,max_size:String(s)});return"".concat(n,"/android/scrcpy/ws?").concat(l.toString())}(l,r));return ej.current=o,o.binaryType="arraybuffer",o.onopen=()=>{em(!0),ep(null),eU(),eC.current=window.setTimeout(()=>{eR.current||i(s("实时画面无首帧,已切回截图模式","No first live frame, using screenshot mode"))},5200)},o.onmessage=e=>{var t;if("string"==typeof e.data){try{let t=JSON.parse(e.data);t.error&&ep(t.error)}catch(e){}return}null===(t=ek.current)||void 0===t||t.push(e.data)},o.onerror=()=>{ep(s("WebSocket 异常","WebSocket error"))},o.onclose=()=>{var e;em(!1),null===(e=ek.current)||void 0===e||e.reset(),ek.current=null,eU(),eo&&!e_.current&&i(s("实时画面连接失败,已切回截图模式","Live stream failed, using screenshot mode"))},()=>{eU(),e_.current=!0,eR.current=!1,o.close(),ej.current=null,a.reset(),ek.current===a&&(ek.current=null)}},[eo,r,c,l,eT,eU,s]),(0,_.useEffect)(()=>{r&&c&&(eS.current=0,f(e=>e+1))},[r,c]);let eI=async()=>{let e=L.trim();if(!e){p(s("填写 host:port","Enter host:port"));return}ei(!0);try{let t=await i("/android/connect",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({address:e})});p(t.message||(t.ok?"OK":s("连接结果见日志","See message"))),b(),eT()}catch(e){p(e.message)}finally{ei(!1)}},eD=async e=>{ei(!0);try{let t=await i("/android/disconnect",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({address:e})});p(t.message||"OK"),b()}catch(e){p(e.message)}finally{ei(!1)}},eA=async()=>{let e=T.trim(),t=parseInt(E,10)||37777,n=D.trim();if(!e||!n){p(s("填写配对 IP 与码","Host + code required"));return}ei(!0);try{let l=await i("/android/pair",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({host:e,port:t,code:n})});p(l.message||(l.ok?s("配对成功后再点连接","Paired — now Connect"):"pair"))}catch(e){p(e.message)}finally{ei(!1)}},eZ=async e=>{if(!R||x||!c||!r)return;let t=ew.current;if(!t)return;let n=X(t,e.clientX,e.clientY);if(!n)return;let l=Date.now(),i=ey.current;i&&l-i.t<320&&28>Math.abs(i.x-n.x)&&28>Math.abs(i.y-n.y)?(ey.current=null,await h("double_tap",{x:n.x,y:n.y}),p(s("双击","Double tap"))):(ey.current={t:l,x:n.x,y:n.y},await h("tap",{x:n.x,y:n.y})),eT()},eO=async e=>{if(e.preventDefault(),x||!c||!r)return;let t=ew.current;if(!t)return;let n=X(t,e.clientX,e.clientY);n&&(await h("long_press",{x:n.x,y:n.y,duration:720}),p(s("长按","Long press")),eT())},eH=async e=>{if(!R||x||!c||!r)return;let t=eN.current;if(!t)return;let n=q(t,e.clientX,e.clientY);if(!n)return;let l=Date.now(),i=ey.current;i&&l-i.t<320&&28>Math.abs(i.x-n.x)&&28>Math.abs(i.y-n.y)?(ey.current=null,await h("double_tap",{x:n.x,y:n.y}),p(s("双击","Double tap"))):(ey.current={t:l,x:n.x,y:n.y},await h("tap",{x:n.x,y:n.y})),eo||eT()},eB=async e=>{if(e.preventDefault(),x||!c||!r)return;let t=eN.current;if(!t)return;let n=q(t,e.clientX,e.clientY);n&&(await h("long_press",{x:n.x,y:n.y,duration:720}),p(s("长按","Long press")),eo||eT())};if(!c)return(0,n.jsx)("div",{className:"rounded-2xl border border-amber-500/25 bg-amber-500/[0.06] p-6 text-center text-sm text-amber-200/90",children:s("宿主机未安装 adb,无法使用 Live 控制台。","adb is required for the Live console.")});let eK=Q(eP),eF=eK.Icon;return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-sky-500/20 bg-gradient-to-br from-sky-500/[0.08] via-zinc-950/80 to-zinc-900/90 p-4 ring-1 ring-white/[0.05]",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2 border-b border-white/[0.06] pb-3",children:[(0,n.jsx)(A.Z,{className:"h-4 w-4 text-sky-400"}),(0,n.jsx)("h4",{className:"text-sm font-semibold text-white",children:s("链路管理","Link manager")}),(0,n.jsx)("span",{className:"text-[10px] text-zinc-500",children:s("USB / Redroid :5555 / 无线调试(先配对再连接)","USB \xb7 Redroid :5555 \xb7 wireless (pair then connect)")})]}),(0,n.jsxs)("div",{className:"mt-3 grid gap-3 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"space-y-2 rounded-xl border border-white/[0.06] bg-black/35 p-3",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"adb connect"}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("input",{className:"min-w-[12rem] flex-1 rounded-lg border border-white/10 bg-black/50 px-3 py-2 font-mono text-xs text-zinc-200",placeholder:"192.168.1.10:5555",value:L,onChange:e=>M(e.target.value),onKeyDown:e=>"Enter"===e.key&&void eI()}),(0,n.jsx)("button",{type:"button",disabled:el||x,onClick:()=>void eI(),className:"rounded-lg bg-sky-500/25 px-3 py-2 text-xs font-semibold text-sky-100 ring-1 ring-sky-400/40",children:el?"…":"Connect"}),(0,n.jsx)("button",{type:"button",disabled:el||x||!L.trim(),onClick:()=>eE(L),className:"rounded-lg border border-white/10 px-3 py-2 text-xs text-zinc-400 hover:text-zinc-200",children:s("存书签","Pin")})]}),er.length?(0,n.jsx)("div",{className:"flex flex-wrap gap-1.5 pt-1",children:er.map(e=>(0,n.jsx)("button",{type:"button",className:"rounded-md bg-white/[0.06] px-2 py-0.5 font-mono text-[10px] text-zinc-400 hover:bg-white/10",onClick:()=>M(e),children:e},e))}):null,(0,n.jsxs)("div",{className:"flex flex-wrap gap-2 pt-2",children:[(0,n.jsx)("button",{type:"button",disabled:el||x||!r,onClick:()=>void eD(r),className:"rounded-lg border border-rose-500/30 bg-rose-500/10 px-2.5 py-1.5 text-[10px] text-rose-200",children:s("断开当前 TCP","Disconnect current")}),(0,n.jsx)("button",{type:"button",disabled:el||x,onClick:()=>void eD(""),className:"rounded-lg border border-white/10 px-2.5 py-1.5 text-[10px] text-zinc-500 hover:text-zinc-300",children:s("断开全部 TCP","Disconnect all TCP")}),(0,n.jsxs)("button",{type:"button",disabled:el||x,onClick:()=>{b(),eT(),p(s("已刷新设备列表","Devices refreshed"))},className:"inline-flex items-center gap-1 rounded-lg border border-white/10 px-2.5 py-1.5 text-[10px] text-zinc-400",children:[(0,n.jsx)(y.Z,{className:"h-3 w-3"}),"ADB list"]})]})]}),(0,n.jsxs)("div",{className:"space-y-2 rounded-xl border border-white/[0.06] bg-black/35 p-3",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"adb pair(无线调试)"}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("input",{className:"w-32 rounded-lg border border-white/10 bg-black/50 px-2 py-1.5 font-mono text-xs",placeholder:"IP",value:T,onChange:e=>U(e.target.value)}),(0,n.jsx)("input",{className:"w-20 rounded-lg border border-white/10 bg-black/50 px-2 py-1.5 font-mono text-xs",placeholder:"port",value:E,onChange:e=>I(e.target.value)}),(0,n.jsx)("input",{className:"min-w-[6rem] flex-1 rounded-lg border border-white/10 bg-black/50 px-2 py-1.5 font-mono text-xs tracking-widest",placeholder:"123456",value:D,onChange:e=>en(e.target.value)}),(0,n.jsx)("button",{type:"button",disabled:el||x,onClick:()=>void eA(),className:"rounded-lg bg-violet-500/20 px-3 py-1.5 text-xs text-violet-100 ring-1 ring-violet-400/35",children:"Pair"})]}),(0,n.jsx)("p",{className:"text-[10px] leading-relaxed text-zinc-600",children:s("手机上「无线调试」会显示配对端口与 6 位码;配对成功后用上方 connect 连接 adb 显示的 IP:5555。","Use the pairing port + 6-digit code from Wireless debugging; then connect to the listed adb IP:5555.")})]})]})]}),(0,n.jsxs)("div",{className:"relative overflow-hidden rounded-3xl border border-emerald-500/25 bg-gradient-to-br from-emerald-500/[0.12] via-zinc-950/90 to-violet-500/[0.08] p-1 shadow-2xl shadow-emerald-900/20 ring-1 ring-white/[0.06]",children:[(0,n.jsx)("div",{className:"pointer-events-none absolute -right-20 -top-20 h-56 w-56 rounded-full bg-emerald-500/10 blur-3xl","aria-hidden":!0}),(0,n.jsxs)("div",{className:"relative rounded-[1.35rem] border border-white/[0.06] bg-zinc-950/80 p-4 backdrop-blur-sm",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",children:[(0,n.jsxs)("div",{className:"flex items-start gap-3",children:[(0,n.jsx)("div",{className:"flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-emerald-400/30 to-violet-500/25 ring-1 ring-white/10",children:(0,n.jsx)(m.Z,{className:"h-6 w-6 text-emerald-200"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-base font-semibold tracking-tight text-white",children:s("无人直播系统 \xb7 ADB 云控台","Unmanned Live System \xb7 ADB farm console")}),(0,n.jsxs)("p",{className:"mt-1 max-w-xl text-[11px] leading-relaxed text-zinc-500",children:[s("统一适配 USB / Redroid / 无线 adb:已授权设备默认走官方 scrcpy-server 的 WebSocket H.264 真流(与桌面 ","USB / Redroid / wireless adb: authorized devices default to official scrcpy-server WebSocket H.264 (same stack as "),(0,n.jsx)("a",{href:et,target:"_blank",rel:"noreferrer",className:"text-emerald-300/90 underline-offset-2 hover:underline",children:"escrcpy"}),s(" / "," / "),(0,n.jsx)("a",{href:ee,target:"_blank",rel:"noreferrer",className:"text-emerald-300/90 underline-offset-2 hover:underline",children:"scrcpy"}),s(");无 jar 或关闭真流时用截图。","); PNG screenshot when jar missing or stream off.")]})]})]}),(0,n.jsxs)("div",{className:"flex shrink-0 flex-col gap-1.5 self-start sm:flex-row",children:[(0,n.jsxs)("a",{href:et,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-xl border border-white/10 bg-white/[0.04] px-3 py-2 text-[11px] font-medium text-zinc-300 hover:bg-white/[0.07]",children:["escrcpy",(0,n.jsx)(Z.Z,{className:"h-3.5 w-3.5 opacity-70"})]}),(0,n.jsxs)("a",{href:ee,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-xl border border-white/10 bg-white/[0.04] px-3 py-2 text-[11px] font-medium text-zinc-300 hover:bg-white/[0.07]",children:["scrcpy",(0,n.jsx)(Z.Z,{className:"h-3.5 w-3.5 opacity-70"})]})]})]}),a.length>0?(0,n.jsxs)("div",{className:"mt-5",children:[(0,n.jsxs)("p",{className:"mb-2 flex items-center gap-2 text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:[(0,n.jsx)(O.Z,{className:"h-3.5 w-3.5"}),s("设备矩阵","Device matrix")]}),(0,n.jsx)("div",{className:"flex gap-2 overflow-x-auto pb-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",children:a.map(e=>{let t="device"===e.state,l=r===e.serial,i=Q(e.transport),a=i.Icon;return(0,n.jsxs)("button",{type:"button",onClick:()=>o(e.serial),className:"flex min-w-[9rem] flex-col rounded-xl border px-3 py-2 text-left transition ".concat(l?"border-emerald-500/50 bg-emerald-500/15 ring-1 ring-emerald-400/30":"border-white/10 bg-black/30 hover:border-white/20"),children:[(0,n.jsxs)("span",{className:"flex items-center gap-1.5 text-xs font-medium text-zinc-200",children:[(0,n.jsx)(d.Z,{className:"h-3.5 w-3.5 text-emerald-400/80"}),(0,n.jsx)("span",{className:"truncate",children:e.model||e.serial.slice(0,10)})]}),(0,n.jsx)("span",{className:"mt-0.5 truncate font-mono text-[9px] text-zinc-600",children:e.serial}),(0,n.jsxs)("div",{className:"mt-1 flex flex-wrap gap-1",children:[(0,n.jsxs)("span",{className:"inline-flex items-center gap-0.5 rounded-md px-1.5 py-0.5 text-[9px] font-semibold ring-1 ".concat(i.cls),children:[(0,n.jsx)(a,{className:"h-2.5 w-2.5"}),s(i.zh,i.en)]}),(0,n.jsx)("span",{className:"rounded-md px-1.5 py-0.5 text-[9px] font-semibold ".concat(t?"bg-emerald-500/20 text-emerald-200":"bg-zinc-600/30 text-zinc-500"),children:e.state})]})]},e.serial)})})]}):null,(0,n.jsxs)("div",{className:"mt-6 grid gap-6 xl:grid-cols-12",children:[(0,n.jsxs)("div",{className:"xl:col-span-8",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2 border-b border-white/[0.06] pb-3",children:[(0,n.jsx)("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:s("刷新间隔","Interval")}),$.map(e=>(0,n.jsx)("button",{type:"button",onClick:()=>w(e),className:"rounded-lg px-2.5 py-1 text-[10px] font-semibold transition ".concat(v===e?"bg-violet-500/25 text-violet-100 ring-1 ring-violet-400/35":"bg-black/30 text-zinc-500 hover:text-zinc-300"),children:0===e?s("手动","Manual"):"".concat(e,"ms")},e)),(0,n.jsxs)("span",{className:"ml-1 inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-[9px] font-medium ring-1 ".concat(eK.cls),children:[(0,n.jsx)(eF,{className:"h-3 w-3"}),"tcp"===eP?s("建议 ≥450ms","Suggest ≥450ms"):s("可试 280ms","Try 280ms")]}),(0,n.jsxs)("button",{type:"button",disabled:x,onClick:()=>void eT(),className:"ml-auto inline-flex items-center gap-1 rounded-lg border border-white/10 bg-white/[0.05] px-2.5 py-1 text-[10px] text-zinc-300 hover:bg-white/[0.08]",children:[(0,n.jsx)(y.Z,{className:"h-3 w-3 ".concat(N?"animate-spin":"")}),s("下一帧","Next frame")]}),(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>void h("wake"),className:"rounded-lg bg-amber-500/20 px-2.5 py-1 text-[10px] font-semibold text-amber-100 ring-1 ring-amber-500/30",children:"Wake"}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-1.5 text-[10px] text-zinc-400",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/50",checked:R,onChange:e=>P(e.target.checked)}),(0,n.jsx)(H.Z,{className:"h-3 w-3"}),s("点按穿透","Tap-through")]}),(0,n.jsxs)("button",{type:"button",disabled:x||!r||!(null==eb?void 0:eb.server_jar),title:eb&&!eb.server_jar&&eb.hint_zh?eb.hint_zh:s("官方 scrcpy-server + WebSocket H.264","Official scrcpy-server + WebSocket H.264"),onClick:()=>{ec(e=>{let t=!e;return t?(ex(null),p(s("已开启实时画面(H.264 WebSocket)","Live H.264 WebSocket stream on"))):(r&&ex(r),p(s("已关闭实时画面(将使用截图)","Live stream off — screenshot mode"))),t})},className:"inline-flex items-center gap-1 rounded-lg border px-2.5 py-1 text-[10px] font-semibold transition ".concat(eo?"border-cyan-400/50 bg-cyan-500/20 text-cyan-100 ring-1 ring-cyan-400/35":"border-white/10 bg-black/30 text-zinc-400 hover:text-zinc-200"),children:[(0,n.jsx)(B.Z,{className:"h-3 w-3"}),eo?s("关闭真流","Stop WS"):s("实时画面","Live H.264")]})]}),eb&&!eb.server_jar?(0,n.jsxs)("p",{className:"mt-2 text-[10px] text-amber-200/80",children:[s("未检测到 scrcpy-server:启动时会自动拉取;内网可在 runtime.env 配置 SCRCPY_SERVER_DOWNLOAD_URL(支持 {tag})。","scrcpy-server missing: auto-fetched on startup; set SCRCPY_SERVER_DOWNLOAD_URL ({tag}) for mirrors."),eb.server_version?" (".concat(s("期望版本","version")," ").concat(eb.server_version,")"):null]}):null,(0,n.jsx)("p",{className:"mt-2 text-[10px] text-zinc-600",children:s("快捷键(镜像区聚焦时):H Home \xb7 B Back \xb7 R 多任务 \xb7 W 唤醒 \xb7 M 菜单","Hotkeys (mirror focused): H Home \xb7 B Back \xb7 R Recents \xb7 W Wake \xb7 M Menu")}),(0,n.jsxs)("div",{className:"relative mx-auto mt-4 max-h-[min(78vh,720px)] min-h-[280px]",children:[r?(0,n.jsxs)("div",{ref:ez,tabIndex:0,onKeyDown:e=>{if(!r||x)return;let t=e.target.tagName;if("INPUT"===t||"TEXTAREA"===t||"SELECT"===t)return;let s={h:["key",{keycode:"3"}],b:["key",{keycode:"4"}],r:["key",{keycode:"187"}],w:["wake",void 0],m:["key",{keycode:"82"}]}[e.key.toLowerCase()];s&&(e.preventDefault(),(async()=>{await h(s[0],s[1]),eo||eT()})())},className:"relative flex justify-center outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/50",children:[(0,n.jsxs)("div",{className:"relative rounded-[2rem] border-[10px] border-zinc-800 bg-black shadow-inner shadow-black/80 ring-1 ring-white/10",style:{maxHeight:"min(72vh, 680px)"},children:[(0,n.jsx)("div",{className:"absolute left-1/2 top-0 z-10 h-5 w-24 -translate-x-1/2 rounded-b-xl bg-black/80"}),eo?(0,n.jsx)("canvas",{ref:eN,className:"max-h-[min(72vh,680px)] w-auto max-w-full rounded-[1.35rem] object-contain ".concat(R?"cursor-crosshair":"cursor-default"),draggable:!1,onClick:eH,onContextMenu:eB}):(0,n.jsx)("img",{ref:ew,src:eM||void 0,alt:"device",className:"max-h-[min(72vh,680px)] w-auto max-w-full rounded-[1.35rem] object-contain ".concat(R?"cursor-crosshair":"cursor-default"),draggable:!1,onLoadStart:()=>{j(!0)},onLoad:()=>{j(!1),eS.current=0,z(null)},onError:()=>{j(!1),eS.current+=1,eS.current<=3?(z(null),window.setTimeout(()=>eT(),380+200*eS.current)):z(s("截图连续失败:检查 USB 授权 / 无线是否断开 / Redroid 端口","Screenshot failed repeatedly"))},onClick:eZ,onContextMenu:eO})]}),eu?(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1 rounded-full bg-cyan-500/90 px-2 py-0.5 text-[9px] font-bold text-cyan-950 shadow-lg",children:[(0,n.jsx)(B.Z,{className:"h-3 w-3"}),"SCRCPY\xb7WS"]}):v>0&&!eo?(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1 rounded-full bg-emerald-500/90 px-2 py-0.5 text-[9px] font-bold text-emerald-950 shadow-lg",children:[(0,n.jsx)(K.Z,{className:"h-3 w-3"}),"LIVE"]}):eo?null:(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1 rounded-full bg-zinc-700/90 px-2 py-0.5 text-[9px] font-bold text-zinc-200",children:[(0,n.jsx)(F.Z,{className:"h-3 w-3"}),s("单帧","Still")]})]}):(0,n.jsx)("p",{className:"py-16 text-center text-sm text-zinc-600",children:s("请选择或连接设备","Pick or connect a device")}),eh?(0,n.jsx)("p",{className:"mt-3 text-center text-xs text-rose-300",children:eh}):null,k&&!eo?(0,n.jsx)("p",{className:"mt-3 text-center text-xs text-rose-300",children:k}):null,(0,n.jsx)("p",{className:"mt-3 text-center text-[10px] text-zinc-600",children:s("左键单击 / 双击 \xb7 右键长按 \xb7 坐标对齐 PNG 像素","Left tap/double \xb7 right long-press \xb7 PNG pixel coords")})]})]}),(0,n.jsxs)("div",{className:"space-y-4 xl:col-span-4",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.07] bg-black/40 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:s("遥测","Telemetry")}),u?(0,n.jsxs)("dl",{className:"mt-3 space-y-2 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"device"}),(0,n.jsxs)("dd",{className:"text-right text-zinc-200",children:[u.brand," ",u.model]})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"Android"}),(0,n.jsxs)("dd",{className:"text-zinc-300",children:[u.android_version," (API ",u.sdk,")"]})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"wm size"}),(0,n.jsx)("dd",{className:"text-cyan-300/90",children:S?"".concat(S.width,"\xd7").concat(S.height):u.resolution||"—"})]}),(0,n.jsx)("div",{className:"whitespace-pre-wrap text-[10px] leading-snug text-zinc-500",children:u.battery})]}):(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-600",children:s("在上方点「刷新设备信息」","Use Refresh device info above")})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/20 bg-gradient-to-b from-violet-500/[0.08] to-black/40 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-violet-300/80",children:s("导航坞","Nav dock")}),(0,n.jsx)("div",{className:"mt-3 grid grid-cols-3 gap-2",children:[["3","Home"],["4","Back"],["187","Recents"]].map(e=>{let[t,s]=e;return(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("key",{keycode:t}),eT()},className:"rounded-xl border border-white/10 bg-white/[0.06] py-3 text-xs font-semibold text-zinc-200 hover:bg-white/[0.1]",children:s},t)})}),(0,n.jsxs)("div",{className:"mt-2 grid grid-cols-2 gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("key",{keycode:"24"}),eT()},className:"rounded-xl border border-white/10 bg-black/30 py-2 text-[11px] text-zinc-300",children:"Vol+"}),(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("key",{keycode:"25"}),eT()},className:"rounded-xl border border-white/10 bg-black/30 py-2 text-[11px] text-zinc-300",children:"Vol−"})]})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-cyan-500/15 bg-cyan-500/[0.05] p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-cyan-300/80",children:s("手势","Gestures")}),(0,n.jsx)("div",{className:"mt-2 grid grid-cols-2 gap-2",children:["up","down","left","right"].map(e=>(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("swipe",{direction:e}),eT()},className:"rounded-lg border border-white/10 bg-black/30 py-2 font-mono text-[10px] uppercase text-zinc-300",children:e},e))})]})]})]})]})]})]})}let el=[{label:"getprop",cmd:"getprop ro.build.version.release"},{label:"top pkg",cmd:"dumpsys activity activities | grep -E 'mResumedActivity' | tail -n 1"},{label:"usb",cmd:"dumpsys usb | head -n 60"},{label:"surface",cmd:"dumpsys SurfaceFlinger | head -n 40"}];function ei(e,t,s){return e?(0,n.jsx)("span",{className:"rounded bg-emerald-500/15 px-2 py-0.5 text-[10px] text-emerald-200",children:t}):(0,n.jsx)("span",{className:"rounded bg-zinc-500/15 px-2 py-0.5 text-[10px] text-zinc-400",children:s})}function er(e){var t,s,l,i,r,a,o,c,d,x,u,m,h,p,b;let{t:g,notify:f,fetchJson:y,apiBase:w,busy:N,androidSerial:j,setAndroidSerial:k,devices:z,adbAvailable:S,apkPath:C,setApkPath:R,onAndroidAction:P,onCopy:I,onRefreshDevices:D}=e,[A,Z]=(0,_.useState)(null),[O,H]=(0,_.useState)(null),[B,K]=(0,_.useState)(null),[F,W]=(0,_.useState)(null),[Y,J]=(0,_.useState)(""),[G,V]=(0,_.useState)([]),[q,X]=(0,_.useState)("getprop ro.product.model"),[$,Q]=(0,_.useState)(""),[ee,et]=(0,_.useState)("300"),[es,er]=(0,_.useState)(""),[ea,eo]=(0,_.useState)(null),[ec,ed]=(0,_.useState)([]),[ex,eu]=(0,_.useState)(null),[em,eh]=(0,_.useState)("https://"),[ep,eb]=(0,_.useState)(""),[eg,ef]=(0,_.useState)(!1),[ev,ey]=(0,_.useState)(null),ew=!!(N||ev),eN=z.find(e=>e.serial===j)||null,ej=(0,_.useCallback)(async()=>{if(!j||!S){Z(null),H(null);return}ey("overview"),H(null);try{let e=await y("/android/overview?serial=".concat(encodeURIComponent(j)));Z(e)}catch(e){Z(null),H(e.message)}finally{ey(null)}},[S,j,y]),ek=(0,_.useCallback)(async()=>{W(null);try{let e=await y("/redroid/summary");K(e)}catch(e){K(null),W(e.message)}},[y]);(0,_.useEffect)(()=>{ej()},[ej]),(0,_.useEffect)(()=>{ek()},[ek]);let ez=async()=>{if(!j){f(g("请选择设备","Pick a device"));return}ey("packages");try{let e=encodeURIComponent(Y.trim()),t=await y("/android/packages?serial=".concat(encodeURIComponent(j),"&query=").concat(e,"&limit=80"));V(t.packages||[])}catch(e){f(e.message),V([])}finally{ey(null)}},eS=async()=>{if(!j){f(g("请选择设备","Pick a device"));return}let e=q.trim();if(e){ey("shell");try{var t,s;let n=await y("/android/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"shell",serial:j,payload:{command:e}})});Q(null!==(s=null!==(t=n.output)&&void 0!==t?t:n.message)&&void 0!==s?s:"")}catch(e){Q(e.message)}finally{ey(null)}}},e_=(0,_.useCallback)(async e=>{if(!j)return;let t=Math.min(3e3,Math.max(1,parseInt(ee,10)||200)),s=!!(null==e?void 0:e.silent);s||ey("logcat"),eo(null);try{var n;let e=await y("/android/logcat?serial=".concat(encodeURIComponent(j),"&lines=").concat(t));er(null!==(n=e.text)&&void 0!==n?n:"")}catch(e){er(""),eo(e.message)}finally{s||ey(null)}},[j,y,ee]);(0,_.useEffect)(()=>{if(!eg||!j||!S)return;let e=window.setInterval(()=>void e_({silent:!0}),3e3);return e_({silent:!0}),()=>clearInterval(e)},[S,j,eg,e_]);let eC=async()=>{if(!j){f(g("请选择设备","Pick a device"));return}ey("ui"),eu(null);try{let e=await y("/android/ui?serial=".concat(encodeURIComponent(j),"&limit=100"));ed(e.nodes||[])}catch(e){ed([]),eu(e.message)}finally{ey(null)}},eR=async(e,t)=>{ey("redroid:".concat(e));try{let s=await y("/redroid/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,name:t||""})});s.summary&&K(s.summary),f(s.message||"OK"),await ek(),D()}catch(e){f(e.message)}finally{ey(null)}},eP=async e=>{await P("key",{keycode:e})},eL=async()=>{let e=ep.trim();if(!e){f(g("请输入文字","Enter text"));return}await P("text",{text:e})},eM=async()=>{let e=em.trim();if(!e||"https://"===e){f(g("请输入 URL","Enter URL"));return}await P("open_url",{url:e})};return(0,n.jsxs)("div",{className:"mx-auto max-w-6xl space-y-6",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:g("安卓设备工作台","Android workstation")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:g("USB 真机与 Redroid 共用一套控制面,优先保证 USB 真机稳定。","USB phone and Redroid share one control surface.")})]}),S?(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ew||!j,onClick:()=>void ej(),className:"rounded-lg border border-white/10 bg-white/[0.05] px-3 py-1.5 text-xs text-zinc-300",children:g("刷新设备","Refresh device")}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>{ek(),D()},className:"rounded-lg border border-white/10 bg-white/[0.05] px-3 py-1.5 text-xs text-zinc-300",children:g("刷新 Redroid","Refresh Redroid")})]}):(0,n.jsx)("span",{className:"text-xs text-amber-200/90",children:g("宿主机未检测到 adb","adb not found on host")})]}),(0,n.jsx)("div",{className:"mt-4 flex flex-wrap gap-2",children:z.map(e=>(0,n.jsxs)("button",{type:"button",onClick:()=>k(e.serial),className:"rounded-xl border px-4 py-2 text-left text-xs ".concat(j===e.serial?"border-violet-500/50 bg-violet-500/10 text-white":"border-white/10 bg-black/30 text-zinc-400"),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("span",{className:"font-medium text-zinc-200",children:e.model||e.serial}),e.transport?(0,n.jsx)("span",{className:"rounded bg-white/10 px-1.5 py-0.5 font-mono text-[9px] uppercase text-zinc-500",children:e.transport}):null,e.kind?(0,n.jsx)("span",{className:"rounded bg-cyan-500/10 px-1.5 py-0.5 font-mono text-[9px] uppercase text-cyan-200",children:e.kind}):null]}),(0,n.jsx)("div",{className:"text-[10px] text-zinc-600",children:e.serial}),"device"!==(e.state||"").toLowerCase()?(0,n.jsx)("div",{className:"mt-1 text-[10px] font-medium text-amber-200/90",children:"unauthorized"===e.state?g("未授权,请在手机上允许 USB 调试。","Unauthorized, allow USB debugging on device."):"".concat(g("状态","State"),": ").concat(e.state)}):null]},e.serial))}),S&&0===z.length?(0,n.jsx)("p",{className:"mt-4 rounded-lg border border-amber-500/20 bg-amber-500/5 p-3 text-xs leading-relaxed text-amber-200/90",children:g("当前没有已授权设备。USB 真机请检查调试授权;Redroid 请先启动实例,再 adb connect 127.0.0.1:5555。","No authorized devices. For USB phones, confirm USB debugging. For Redroid, start an instance then adb connect 127.0.0.1:5555.")}):null]}),(0,n.jsxs)("div",{className:"grid gap-4 xl:grid-cols-[1.1fr_0.9fr]",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/15 bg-zinc-950/50 p-5",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-violet-300/90",children:g("真机诊断","Phone diagnostics")}),O?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:O}):null,A?(0,n.jsxs)("div",{className:"mt-3 space-y-3",children:[(0,n.jsxs)("dl",{className:"space-y-1.5 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"model"})," ",(0,n.jsxs)("dd",{className:"inline text-zinc-300",children:[A.brand," ",A.model]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"android"})," ",(0,n.jsxs)("dd",{className:"inline text-zinc-300",children:[A.android_version," (sdk ",A.sdk,")"]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"kind"})," ",(0,n.jsxs)("dd",{className:"inline text-zinc-300",children:[A.kind||(null==eN?void 0:eN.kind)||"unknown"," / ",A.transport||(null==eN?void 0:eN.transport)||"unknown"]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"display"})," ",(0,n.jsx)("dd",{className:"inline text-zinc-300",children:A.resolution})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"rotation"})," ",(0,n.jsx)("dd",{className:"inline text-zinc-300",children:A.rotation})]}),(0,n.jsx)("div",{className:"whitespace-pre-wrap text-[10px] leading-snug text-zinc-500",children:A.battery}),(0,n.jsx)("div",{className:"line-clamp-3 text-[10px] text-zinc-500",children:A.focus})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[ei(null===(t=A.diagnostics)||void 0===t?void 0:t.ready,g("已启动","Boot ready"),g("未完成启动","Boot pending")),ei(null===(s=A.diagnostics)||void 0===s?void 0:s.google_play,"Google Play","No Play"),ei(null===(l=A.diagnostics)||void 0===l?void 0:l.google_services,"GMS","No GMS"),ei(null===(i=A.diagnostics)||void 0===i?void 0:i.magisk,"Magisk","No Magisk"),ei(null===(r=A.diagnostics)||void 0===r?void 0:r.root,"Root","No root")]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/5 bg-black/20 p-3 text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{children:["boot_completed: ",(null===(a=A.diagnostics)||void 0===a?void 0:a.boot_completed)||"-"]}),(0,n.jsxs)("div",{children:["provisioned: ",(null===(o=A.diagnostics)||void 0===o?void 0:o.device_provisioned)||"-"]}),(0,n.jsxs)("div",{children:["setup_complete: ",(null===(c=A.diagnostics)||void 0===c?void 0:c.user_setup_complete)||"-"]}),(0,n.jsxs)("div",{children:["abi: ",(null===(d=A.diagnostics)||void 0===d?void 0:d.abi)||"-"]}),(0,n.jsxs)("div",{className:"truncate",children:["hardware: ",(null===(x=A.diagnostics)||void 0===x?void 0:x.hardware)||"-"]})]})]}):O?null:(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:g("加载中","Loading")})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-cyan-500/15 bg-zinc-950/50 p-5",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-cyan-300/90",children:g("Redroid 板块","Redroid panel")}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("start"),className:"rounded-lg bg-emerald-500/20 px-3 py-1.5 text-xs text-emerald-100 ring-1 ring-emerald-500/30",children:g("启动默认实例","Start default")})]}),F?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:F}):null,B?(0,n.jsxs)("div",{className:"mt-3 space-y-3 text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/5 bg-black/20 p-3",children:[(0,n.jsxs)("div",{children:["arch: ",B.arch||"-"]}),(0,n.jsxs)("div",{className:"truncate",children:["image: ",B.image||"-"]}),(0,n.jsxs)("div",{children:["profile: ",B.device_profile||"-"]}),(0,n.jsxs)("div",{children:["gpu: ",B.gpu_mode||"-"]}),(0,n.jsxs)("div",{children:["adb: 127.0.0.1:",B.default_port||5555]})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[ei(null===(u=B.requirements)||void 0===u?void 0:u.docker_available,"Docker","No Docker"),ei(null===(m=B.requirements)||void 0===m?void 0:m.adb_available,"ADB","No ADB"),ei(null===(h=B.requirements)||void 0===h?void 0:h.kvm,"KVM","No KVM"),ei(null===(p=B.requirements)||void 0===p?void 0:p.binderfs,"binderfs","No binderfs")]}),(0,n.jsxs)("div",{className:"space-y-2",children:[(B.instances||[]).map(e=>{var t,s,l,i;return(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/25 p-3",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-medium text-zinc-100",children:e.name}),(0,n.jsxs)("div",{className:"font-mono text-[10px] text-zinc-500",children:[e.port?"127.0.0.1:".concat(e.port):"-"," / ",e.status_text||"-"]})]}),(0,n.jsxs)("div",{className:"flex gap-1",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("start",e.name),className:"rounded bg-emerald-500/15 px-2 py-1 text-[10px] text-emerald-200",children:"Start"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("restart",e.name),className:"rounded bg-amber-500/15 px-2 py-1 text-[10px] text-amber-200",children:"Restart"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("adb_connect",e.name),className:"rounded bg-cyan-500/15 px-2 py-1 text-[10px] text-cyan-200",children:"ADB"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("stop",e.name),className:"rounded bg-rose-500/15 px-2 py-1 text-[10px] text-rose-200",children:"Stop"})]})]}),(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap gap-2",children:[ei(null===(t=e.diagnostics)||void 0===t?void 0:t.ready,g("系统就绪","System ready"),g("启动中","Booting")),ei(null===(s=e.diagnostics)||void 0===s?void 0:s.google_play,"Play","No Play"),ei(null===(l=e.diagnostics)||void 0===l?void 0:l.magisk,"Magisk","No Magisk"),ei(null===(i=e.diagnostics)||void 0===i?void 0:i.root,"Root","No root")]}),e.data_dir?(0,n.jsx)("div",{className:"mt-2 truncate font-mono text-[10px] text-zinc-500",children:e.data_dir}):null]},e.name)}),(null===(b=B.instances)||void 0===b?void 0:b.length)?null:(0,n.jsx)("p",{className:"rounded-xl border border-white/5 bg-black/20 p-3 text-xs text-zinc-500",children:g("当前没有 Redroid 实例。默认动作会创建 redroid13-1。","No Redroid instances yet. Default actions create redroid13-1.")})]})]}):(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:g("读取 Redroid 状态中","Loading Redroid status")})]})]}),(0,n.jsx)(en,{t:g,apiBase:w,fetchJson:y,serial:j,devices:z,setSerial:k,adbAvailable:S,lock:ew,overview:A,onAndroidAction:P,notify:f,onRefreshDevices:D}),S&&j?(0,n.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-5",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-emerald-300/90",children:g("快捷控制","Quick controls")}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("3"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Home"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("4"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Back"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("187"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Recents"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("wake"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Wake"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("launch_package",{package:"com.zhiliaoapp.musically"}),className:"rounded-lg bg-gradient-to-r from-pink-500/25 to-violet-500/25 px-3 py-1.5 text-xs ring-1 ring-white/10",children:"TikTok"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("24"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Vol+"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("25"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Vol-"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("66"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Enter"})]}),(0,n.jsx)("p",{className:"mt-3 text-[10px] text-zinc-600",children:g("滑动手势","Swipe gestures")}),(0,n.jsx)("div",{className:"mt-1 flex flex-wrap gap-2",children:["up","down","left","right"].map(e=>(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("swipe",{direction:e}),className:"rounded-lg border border-white/10 bg-black/30 px-2.5 py-1 font-mono text-[10px] uppercase text-zinc-300",children:e},e))}),(0,n.jsxs)("div",{className:"mt-4 rounded-lg border border-white/5 bg-black/20 p-3",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:g("ADB 文本输入","ADB text input")}),(0,n.jsxs)("div",{className:"mt-2 flex flex-col gap-2 sm:flex-row",children:[(0,n.jsx)("input",{className:"min-w-0 flex-1 rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-xs",value:ep,onChange:e=>eb(e.target.value),placeholder:"hello / 123",onKeyDown:e=>{"Enter"===e.key&&eL()}}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eL(),className:"rounded-lg bg-emerald-500/20 px-3 py-2 text-xs text-emerald-100 ring-1 ring-emerald-500/30",children:g("发送","Send")})]})]}),(0,n.jsxs)("div",{className:"mt-4 flex flex-col gap-2 sm:flex-row sm:items-center",children:[(0,n.jsx)("input",{className:"min-w-0 flex-1 rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-xs",value:em,onChange:e=>eh(e.target.value),placeholder:"https://"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eM(),className:"rounded-lg bg-violet-500/20 px-3 py-2 text-xs text-violet-100 ring-1 ring-violet-500/30",children:g("打开链接","Open URL")})]})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-5",children:[(0,n.jsxs)("h4",{className:"flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-cyan-300/90",children:[(0,n.jsx)(L.Z,{className:"h-4 w-4"}),g("USB 真机优化建议","USB optimization")]}),(0,n.jsxs)("ul",{className:"mt-3 space-y-2 text-xs leading-relaxed text-zinc-400",children:[(0,n.jsx)("li",{children:g("优先使用主板直连 USB,不要经过不稳的 HUB。","Prefer direct motherboard USB, not unstable hubs.")}),(0,n.jsx)("li",{children:g("开发板端固定 adb server,避免频繁 kill-server。","Keep adb server stable and avoid frequent kill-server.")}),(0,n.jsx)("li",{children:g("镜像页默认支持 scrcpy H.264 真流,截图模式作为回退。","Use scrcpy H.264 live stream first, screenshot mode as fallback.")}),(0,n.jsx)("li",{children:g("如果 TikTok / YouTube App 直播,要先确认屏幕常亮、分辨率稳定、USB 供电足够。","For TikTok / YouTube app live, keep screen on, resolution stable, and USB power sufficient.")})]})]})]}):null,S&&j?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(M.Z,{className:"h-4 w-4 text-emerald-400"}),g("包名搜索与启动","Packages")]}),(0,n.jsxs)("div",{className:"mt-3 flex flex-col gap-2 sm:flex-row",children:[(0,n.jsx)("input",{className:"min-w-0 flex-1 rounded-xl border border-white/10 bg-black/40 px-4 py-2 text-sm",value:Y,onChange:e=>J(e.target.value),placeholder:"tiktok / musically / youtube",onKeyDown:e=>{"Enter"===e.key&&ez()}}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void ez(),className:"rounded-xl bg-emerald-500/20 px-4 py-2 text-sm text-emerald-100 ring-1 ring-emerald-500/30",children:g("搜索","Search")})]}),(0,n.jsxs)("ul",{className:"mt-4 max-h-48 space-y-1 overflow-y-auto rounded-lg border border-white/5 bg-black/30 p-2 font-mono text-[11px]",children:[G.map(e=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center justify-between gap-2 py-1 text-zinc-400",children:[(0,n.jsx)("span",{className:"min-w-0 truncate text-zinc-300",children:e.package}),(0,n.jsxs)("span",{className:"flex shrink-0 gap-1",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("launch_package",{package:e.package}),className:"rounded bg-white/10 px-2 py-0.5 text-[10px] text-zinc-200",children:g("启动","Launch")}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("force_stop",{package:e.package}),className:"rounded bg-rose-500/15 px-2 py-0.5 text-[10px] text-rose-200",children:g("停止","Stop")})]})]},e.package)),G.length?null:(0,n.jsx)("li",{className:"py-2 text-center text-zinc-600",children:g("暂无结果","No results")})]})]}):null,S&&j?(0,n.jsxs)("div",{className:"grid gap-6 xl:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(T.Z,{className:"h-4 w-4 text-amber-400"}),"ADB shell"]}),(0,n.jsx)("div",{className:"mt-2 flex flex-wrap gap-1.5",children:el.map(e=>(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>X(e.cmd),className:"rounded-md border border-white/10 bg-white/[0.04] px-2 py-1 text-[10px] text-zinc-400 hover:text-zinc-200",children:e.label},e.label))}),(0,n.jsx)("textarea",{className:"mt-3 min-h-[100px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-3 font-mono text-xs text-zinc-200",value:q,onChange:e=>X(e.target.value),spellCheck:!1,onKeyDown:e=>{"Enter"===e.key&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),eS())}}),(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eS(),className:"rounded-xl bg-amber-500/20 px-4 py-2 text-sm text-amber-100 ring-1 ring-amber-500/30",children:"shell"===ev?(0,n.jsxs)("span",{className:"inline-flex items-center gap-2",children:[(0,n.jsx)(v.Z,{className:"h-3.5 w-3.5 animate-spin"}),"Run"]}):"Run"}),$?(0,n.jsxs)("button",{type:"button",disabled:!$,onClick:()=>I($),className:"inline-flex items-center gap-1 rounded-lg border border-white/10 px-3 py-1.5 text-xs text-zinc-400 hover:text-zinc-200",children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),g("复制输出","Copy")]}):null]}),$?(0,n.jsx)("pre",{className:"mt-3 max-h-64 overflow-auto whitespace-pre-wrap rounded-lg border border-white/5 bg-black/40 p-3 font-mono text-[11px] text-zinc-400 xl:max-h-[min(24rem,50vh)]",children:$}):null]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:g("Logcat","Logcat")}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap items-center gap-2",children:[(0,n.jsx)("input",{className:"w-24 rounded-lg border border-white/10 bg-black/40 px-3 py-2 font-mono text-xs",value:ee,onChange:e=>et(e.target.value)}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2 text-[11px] text-zinc-400",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:eg,onChange:e=>ef(e.target.checked)}),g("每 3 秒自动刷新","Auto every 3s")]}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void e_(),className:"rounded-xl bg-cyan-500/20 px-4 py-2 text-sm text-cyan-100 ring-1 ring-cyan-500/30",children:g("拉取日志","Pull logs")}),es?(0,n.jsxs)("button",{type:"button",onClick:()=>I(es),className:"inline-flex items-center gap-1 rounded-lg border border-white/10 px-3 py-1.5 text-xs text-zinc-400 hover:text-zinc-200",children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),g("复制","Copy")]}):null]}),ea?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:ea}):null,es?(0,n.jsx)("pre",{className:"mt-3 max-h-72 overflow-auto whitespace-pre-wrap rounded-lg border border-white/5 bg-black/50 p-3 font-mono text-[10px] leading-tight text-zinc-500 xl:max-h-[min(24rem,50vh)]",children:es}):null]})]}):null,S&&j?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(E.Z,{className:"h-4 w-4 text-fuchsia-400"}),g("界面节点","UI nodes")]}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eC(),className:"mt-3 rounded-xl border border-fuchsia-500/30 bg-fuchsia-500/10 px-4 py-2 text-sm text-fuchsia-100",children:g("刷新节点","Refresh nodes")}),ex?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:ex}):null,(0,n.jsxs)("ul",{className:"mt-3 max-h-64 space-y-1 overflow-y-auto rounded-lg border border-white/5 bg-black/30 p-2 text-[11px]",children:[ec.map((e,t)=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center justify-between gap-2 border-b border-white/[0.04] py-1.5 text-zinc-400 last:border-0",children:[(0,n.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,n.jsx)("span",{className:"text-zinc-200",children:e.label}),e.resource_id?(0,n.jsx)("span",{className:"ml-2 font-mono text-[10px] text-zinc-600",children:e.resource_id}):null,(0,n.jsxs)("div",{className:"font-mono text-[10px] text-zinc-600",children:["(",e.center_x,", ",e.center_y,")",e.clickable?" click":""]})]}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("tap",{x:e.center_x,y:e.center_y}),className:"shrink-0 rounded bg-white/10 px-2 py-1 text-[10px] text-zinc-200",children:"Tap"})]},"".concat(e.center_x,"-").concat(e.center_y,"-").concat(t))),ec.length||ex?null:(0,n.jsx)("li",{className:"py-4 text-center text-zinc-600",children:g("尚未加载","Not loaded")})]})]}):null,S&&j?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:g("安装 APK","Install APK")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:g("先 adb push 到 /sdcard/ 再执行安装。","Push the APK to /sdcard/ first.")}),(0,n.jsx)("input",{className:"mt-4 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm",value:C,onChange:e=>R(e.target.value)}),(0,n.jsx)("button",{type:"button",disabled:ew||!S||!j,onClick:()=>void P("install_apk",{path:C}),className:"mt-3 rounded-xl bg-emerald-500/20 px-4 py-2 text-sm font-medium text-emerald-100 ring-1 ring-emerald-500/30",children:"pm install"})]}):null]})}var ea=s(9897),eo=s(4554),ec=s(7689),ed=s(8930),ex=s(8401);function eu(e){let{t,title:s,subtitle:l,steps:i,onNavigate:r}=e;return(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/25 bg-gradient-to-br from-violet-500/10 via-zinc-950/40 to-fuchsia-500/5 p-6 shadow-lg shadow-violet-900/10",children:[(0,n.jsx)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:s}),(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-400",children:l}),(0,n.jsx)("div",{className:"mt-6 flex flex-col items-center gap-4 sm:flex-row sm:flex-wrap sm:justify-center",children:i.map((e,t)=>(0,n.jsxs)("div",{className:"flex items-center gap-4",children:[e.openUrl||e.target&&r?(0,n.jsxs)("button",{type:"button",onClick:()=>{if(e.openUrl){window.open((0,ex.p)(e.openUrl),"_blank","noopener,noreferrer");return}e.target&&r&&r(e.target)},className:"flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ring-2 ring-white/10 transition hover:ring-violet-400/50 hover:brightness-110 ".concat(e.gradient),children:[(0,n.jsx)("span",{children:e.label}),e.sub?(0,n.jsx)("span",{className:"mt-1 text-[10px] font-normal text-white/80",children:e.sub}):null]}):(0,n.jsxs)("div",{className:"flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ".concat(e.gradient),children:[(0,n.jsx)("span",{children:e.label}),e.sub?(0,n.jsx)("span",{className:"mt-1 text-[10px] font-normal text-white/80",children:e.sub}):null]}),t8?e.slice(-8):e;if(e.includes("live2/")){let t=e.split("/"),s=t[t.length-1]||"";return s.length>8?s.slice(-8):s}}}let t=e.trim();return!t||t.includes("\n")||t.toLowerCase().startsWith("rtmp")?"":t.length>8?t.slice(-8):t}function eh(e){let t=[];for(let s of e.split(/\r?\n/)){let e=s.trim();if(!e||e.startsWith("#")||!/douyin\.com|v\.douyin\.com/i.test(e))continue;let n=e.match(/(https?:\/\/live\.douyin\.com\/[a-zA-Z0-9_-]+)/i);if(n){t.push(n[1].replace(/^http:\/\//i,"https://"));continue}let l=e.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);if(l){t.push("https://live.douyin.com/".concat(l[1]));continue}let i=e.match(/(\d{8,})/);i&&t.push("https://live.douyin.com/".concat(i[1]))}return Array.from(new Set(t)).slice(0,16)}function ep(e){let t="",s=!0,n="",l=!1,i=e.split(/\r?\n/),r=!1;for(let e of i){let i=e.trim();if(/^\[youtube\]/i.test(i)){r=!0;continue}if(/^\[/.test(i)){r=!1;continue}if(!r||!i||i.startsWith("#")||i.startsWith(";"))continue;let a=i.indexOf("=");if(a<0)continue;let o=i.slice(0,a).trim().toLowerCase(),c=i.slice(a+1).trim().split(/[#;]/)[0].trim();"key"===o||"stream_key"===o?t=c:"rtmps"===o?s=!/^(0|false|否)/i.test(c):"bitrate"===o?n=c:"fast_audio"===o&&(l=/^(1|true|yes|是|开|on)/i.test(c))}return{key:t,rtmps:s,bitrate:n,fastAudio:l}}function eb(e){return"URL_config.".concat(e.replace(/[^a-zA-Z0-9_.-]/g,"_"),".ini")}function eg(e){let t=e.bitrate.trim()?"bitrate = ".concat(e.bitrate.trim()):"# bitrate = 4000";return"[youtube]\n# YouTube 推流 key(工作室 → 直播 → 串流密钥)\nkey = ".concat(e.key.trim(),"\n\n# 使用 RTMPS;填 否 则 RTMP\nrtmps = ").concat(e.rtmps?"是":"否","\n\n# 视频比特率 kbps(可选)\n").concat(t,"\n\n# 轻量音频链,减轻 CPU:1 / 是\nfast_audio = ").concat(e.fastAudio?"1":"0","\n")}function ef(e){if(e<60)return"".concat(e,"s");let t=Math.floor(e/60);return t<60?"".concat(t,"m ").concat(e%60,"s"):"".concat(Math.floor(t/60),"h ").concat(t%60,"m")}function ev(e){var t,s,l;let{t:i,currentProc:r,fetchJson:a,urlListText:o,keySuffixUi:c,showKeyRow:d=!0,pollMs:x=1e3,refreshToken:u=0}=e,[m,h]=(0,_.useState)(""),[p,b]=(0,_.useState)(""),[g,f]=(0,_.useState)(""),[v,w]=(0,_.useState)(""),[N,j]=(0,_.useState)(""),[k,z]=(0,_.useState)([]),[S,C]=(0,_.useState)(null),[R,P]=(0,_.useState)(!1),[L,M]=(0,_.useState)(null),[T,U]=(0,_.useState)(0),[E,I]=(0,_.useState)(!0),D=(0,_.useRef)(null),A=(0,_.useRef)(null),O=(0,_.useRef)(!1),H=(0,_.useRef)(!1),B=(0,_.useRef)(!1),W=(0,_.useRef)(r),Y=(0,_.useRef)(0),J=function(e){let t=[];for(let s of e.split(/\r?\n/)){let e=s.trim();if(!e||e.startsWith("#")||!/douyin\.com|v\.douyin\.com/i.test(e))continue;let n=e.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);if(n){t.push(n[1]);continue}let l=e.match(/(\d{8,})/);t.push(l?l[1]:e.slice(0,96))}return Array.from(new Set(t)).slice(0,12)}(o),G=/^(online|running)$/i.test(m),V=function(e){if(!e)return null;let t=null;for(let s of e.split(/\r?\n/)){let e=s.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);e&&(t=e[1]);let n=s.match(/https?:\/\/[^/\s]*douyin\.com\/(\d{8,})/i);n&&(t=n[1])}return t}(p),q=null!==(s=eh(o)[0])&&void 0!==s?s:"",X=V||(null!==(l=null===(t=q.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i))||void 0===t?void 0:t[1])&&void 0!==l?l:null),$=X?"https://live.douyin.com/".concat(X):q||null,Q=(0,_.useCallback)(async()=>{let e=W.current.trim();if(!e)return;if(H.current){B.current=!0;return}H.current=!0;let t=++Y.current;try{let s=await a("/status?process=".concat(encodeURIComponent(e)));if(t!==Y.current||e!==W.current.trim())return;let n=s.process_status||"unknown";h(n),b(s.recent_log||""),f(s.recent_error||""),w(s.business_status||""),j(s.business_note||""),z(Array.isArray(s.ffmpeg_pids)?s.ffmpeg_pids:[]),C("number"==typeof s.log_age_seconds?s.log_age_seconds:null);let l=/^(online|running)$/i.test(n);l&&!O.current&&M(Date.now()),l||M(null),O.current=l}catch(s){if(t!==Y.current||e!==W.current.trim())return;h("error"),w("error"),j(""),z([]),C(null)}finally{H.current=!1,B.current&&(B.current=!1,window.setTimeout(()=>void Q(),0))}},[a]);(0,_.useEffect)(()=>{if(W.current=r,Y.current+=1,B.current=!1,!r){h(""),b(""),f(""),w(""),j(""),z([]),C(null),M(null),O.current=!1;return}h(""),b(""),f(""),w(""),j(""),z([]),C(null),M(null),O.current=!1,Q()},[r,Q]),(0,_.useEffect)(()=>{let e=()=>I("visible"===document.visibilityState);return e(),document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[]),(0,_.useEffect)(()=>{r&&Q()},[r,Q,u]),(0,_.useEffect)(()=>{if(R||!E||!r)return;let e=window.setInterval(()=>void Q(),x);return()=>clearInterval(e)},[R,E,r,Q,x]),(0,_.useEffect)(()=>{let e=()=>{"visible"===document.visibilityState&&Q()};return document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[Q]),(0,_.useEffect)(()=>{if(!L)return;let e=window.setInterval(()=>U(e=>e+1),1e3);return()=>clearInterval(e)},[L]),(0,_.useEffect)(()=>{if(R||!E)return;let e=D.current;e&&(e.scrollTop=e.scrollHeight)},[p,R,E]),(0,_.useEffect)(()=>{if(R||!E)return;let e=A.current;e&&(e.scrollTop=e.scrollHeight)},[g,R,E]);let ee=null==L?i("—(未检测到在线)","— (not online)"):ef(Math.max(0,Math.floor((Date.now()-L)/1e3))),et=R?i("已暂停刷新","Paused"):E?i("每秒刷新","~1s refresh"):i("后台暂停","Hidden"),es=R?"bg-amber-500/20 text-amber-100 ring-amber-500/35":E?"bg-emerald-500/15 text-emerald-200/90 ring-emerald-500/25":"bg-sky-500/15 text-sky-100 ring-sky-500/25";return(0,n.jsxs)("section",{className:"rounded-2xl border border-emerald-500/20 bg-gradient-to-b from-emerald-500/[0.07] to-zinc-950/80 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsx)("span",{className:"sr-only","aria-hidden":!0,children:T}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:i("当前直播日志","Live process log")}),(0,n.jsx)("span",{className:"rounded-full bg-white/10 px-2 py-0.5 font-mono text-[10px] text-zinc-300 ring-1 ring-white/10",children:r||"—"}),(0,n.jsx)("span",{className:"rounded-full px-2 py-0.5 text-[10px] font-medium ring-1 ".concat(es),children:et})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsxs)("button",{type:"button",onClick:()=>void Q(),className:"inline-flex items-center gap-1 rounded-lg border border-white/10 bg-white/[0.05] px-3 py-1.5 text-xs text-zinc-300 hover:bg-white/[0.08]",children:[(0,n.jsx)(y.Z,{className:"h-3.5 w-3.5"}),i("立即拉取","Refresh")]}),(0,n.jsxs)("button",{type:"button",onClick:()=>P(e=>!e),className:"inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-xs ring-1 ".concat(R?"bg-amber-500/20 text-amber-100 ring-amber-500/35":"border border-white/10 bg-black/30 text-zinc-300"),children:[R?(0,n.jsx)(K.Z,{className:"h-3.5 w-3.5"}):(0,n.jsx)(F.Z,{className:"h-3.5 w-3.5"}),R?i("继续自动刷新","Resume"):i("暂停自动刷新","Pause")]})]})]}),(0,n.jsxs)("div",{className:"mt-4 space-y-3 rounded-xl border border-white/[0.06] bg-black/25 p-4",children:[(0,n.jsxs)("div",{className:"grid gap-2 text-xs sm:grid-cols-2",children:[(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("进程状态","Status")}),(0,n.jsx)("span",{className:"font-medium text-zinc-200",children:function(e,t){let s=(t||"unknown").toLowerCase();return"online"===s||"running"===s?e("运行中(PM2/进程在线)","Running (process online)"):"stopped"===s||"stopping"===s?e("已停止","Stopped"):"not_found"===s||"errored"===s?e("未运行或未找到","Not running / not found"):"invalid"===s?e("无效进程名","Invalid process"):t||"—"}(i,m)})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("Business state","Business state")}),(0,n.jsx)("span",{className:"font-medium text-cyan-200/90",children:function(e,t,s){let n=(t||"").toLowerCase();return"streaming"===n?e("Pushing to YouTube","Pushing to YouTube"):"waiting_source"===n?e("Waiting for the upstream live source","Waiting for the upstream live source"):"source_live"===n?e("Source live detected, but no active FFmpeg relay worker","Source live detected, but no active FFmpeg relay worker"):"monitoring"===n?e("Process online and monitoring the source","Process online and monitoring the source"):"misconfigured"===n?e("YouTube key missing or invalid","YouTube key missing or invalid"):"stale"===n?e("Process online but the log heartbeat is stale","Process online but the log heartbeat is stale"):"error"===n?e("Recent process error detected","Recent process error detected"):(null==s?void 0:s.trim())?s.trim():e("No business-state hint yet","No business-state hint yet")}(i,v,N)})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("本次在线时长(估算)","Online duration (est.)")}),(0,n.jsx)("span",{className:"font-mono text-cyan-200/90",children:ee})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("FFmpeg workers","FFmpeg workers")}),(0,n.jsxs)("span",{className:"font-mono text-zinc-300",children:[k.length?k.join(", "):"none",null!=S?" \xb7 log ".concat(ef(Math.max(0,Math.floor(S)))):""]})]})]}),d?(0,n.jsxs)("div",{className:"flex flex-wrap gap-2 text-xs",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("YouTube key 尾码(参考)","YT key suffix")}),(0,n.jsx)("span",{className:"font-mono text-zinc-300",children:c||"—"})]}):null,$?(0,n.jsxs)("div",{className:"rounded-lg border border-violet-500/20 bg-violet-500/[0.06] px-3 py-2.5",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsx)("span",{className:"text-[11px] font-medium text-zinc-400",children:V?i("当前直播源站(日志)","Current source (from log)"):G?i("配置中的源站地址","Configured source URL"):i("源站快捷入口","Source quick link")}),(0,n.jsxs)("a",{href:$,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-lg bg-violet-500/20 px-3 py-1.5 text-xs font-medium text-violet-100 ring-1 ring-violet-500/35 transition hover:bg-violet-500/30",children:[(0,n.jsx)(Z.Z,{className:"h-3.5 w-3.5 shrink-0 opacity-90"}),X||i("打开抖音直播页","Open Douyin live")]})]}),J.length>1&&V?(0,n.jsxs)("p",{className:"mt-2 text-[10px] text-zinc-600",children:[i("配置中还有","Also in config:")," ",J.filter(e=>e!==X).slice(0,3).map(e=>(0,n.jsx)("a",{href:"https://live.douyin.com/".concat(e),target:"_blank",rel:"noreferrer",className:"ml-1 text-violet-400/90 underline-offset-2 hover:underline",children:e},e)),J.length>4?"…":null]}):null]}):(0,n.jsx)("p",{className:"text-[11px] text-zinc-600",children:i("(日志与地址列表中暂无抖音房间)","(No Douyin room in log or URL list)")})]}),"not_found"!==m&&"invalid"!==m?(0,n.jsxs)("div",{className:"mt-4 grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"text-[11px] font-semibold uppercase tracking-wider text-emerald-400/90",children:i("进程输出(stdout / 合并日志)","Process output")}),(0,n.jsx)("pre",{ref:D,className:"log-live-scroll mt-2 max-h-[min(22rem,42vh)] min-h-[12rem] overflow-auto whitespace-pre-wrap rounded-xl border border-emerald-500/20 bg-black/55 p-3 font-mono text-[10px] leading-relaxed text-emerald-100/95",children:p.trim()||i("(暂无)","(empty)")})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"text-[11px] font-semibold uppercase tracking-wider text-rose-400/90",children:i("异常信息(stderr)","Stderr")}),(0,n.jsx)("pre",{ref:A,className:"log-live-scroll mt-2 max-h-[min(22rem,42vh)] min-h-[12rem] overflow-auto whitespace-pre-wrap rounded-xl border border-rose-500/20 bg-black/55 p-3 font-mono text-[10px] leading-relaxed text-rose-100/95",children:g.trim()||i("(暂无)","(empty)")})]})]}):(0,n.jsx)("p",{className:"mt-4 text-xs text-zinc-500",children:i("进程未在 PM2 / 本地注册表中运行,日志区域已隐藏。","Process not running — log panes hidden.")})]})}function ey(e){return/tiktok/i.test(e.script)||/tiktok/i.test(e.pm2)}let ew=[{id:"720p60",labelZh:"720p @ 60Hz",labelEn:"720p @ 60Hz",spec:"1280x720, 59.94/60Hz, RGB/YUV 有限",hintZh:"板端 HDMI 输出时序与显示端一致;下游画布建议 1280\xd7720。",hintEn:"Match SoC HDMI timing to the display; downstream canvas e.g. 1280\xd7720."},{id:"1080p30",labelZh:"1080p @ 30Hz",labelEn:"1080p @ 30Hz",spec:"1920x1080, 30Hz",hintZh:"带宽紧张时可优先 1080p30;检查线材与接口规格。",hintEn:"Prefer 1080p30 when bandwidth is tight; check cable and port specs."},{id:"1080p60",labelZh:"1080p @ 60Hz",labelEn:"1080p @ 60Hz",spec:"1920x1080, 60Hz, 高刷转播",hintZh:"两端均需稳定支持 1080p60;长时间运行注意散热。",hintEn:"Both ends need stable 1080p60; mind thermals for long runs."}],eN="live-hub-tiktok-hdmi-check-v1",ej="live-hub-tiktok-hdmi-notes-v1",ek="live-hub-tiktok-source-mode-v1";function ez(e){var t;let{t:s,busy:l,entries:i,currentProc:r,setCurrentProc:a,urlConfig:o,setUrlConfig:c,onRunProcess:d,onSaveUrlConfig:x,onReplayGoLive:u,onCopy:m,fetchJson:h,apiPrefix:p,quickLinks:b,hdmiStatus:g,notify:f,onNavigate:v}=e,y=(0,_.useMemo)(()=>i.filter(ey),[i]),w=y.length?y:i,[N,j]=(0,_.useState)("srs"),[k,z]=(0,_.useState)([]),[S,C]=(0,_.useState)(!1),[R,P]=(0,_.useState)(!1),[L,M]=(0,_.useState)("1080p30"),[T,E]=(0,_.useState)("1080p30"),[I,A]=(0,_.useState)(!1),[Z,O]=(0,_.useState)(!0),[H,K]=(0,_.useState)(null),F=(0,_.useRef)(!1),W=(0,_.useRef)(o),[J,G]=(0,_.useState)(""),[V,q]=(0,_.useState)({}),X=(0,_.useCallback)(e=>{W.current=e,c(e)},[c]),$=(0,_.useCallback)(e=>{j(e);try{window.localStorage.setItem(ek,e)}catch(e){}},[]);(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(ek);("ffmpeg"===e||"replay"===e||"srs"===e)&&("ffmpeg"!==e&&"replay"!==e?j(e):j("srs"))}catch(e){}},[]),(0,_.useEffect)(()=>{F.current=!1},[r]),(0,_.useEffect)(()=>{W.current=o},[o]);let Q=(0,_.useCallback)(async()=>{if(r)try{var e;let t=new URLSearchParams({process:r,_ts:String(Date.now())}),s=await h("/get_url_config?".concat(t));X(null!==(e=s.content)&&void 0!==e?e:"")}catch(e){}},[X,r,h]);(0,_.useEffect)(()=>{if(!r||!Z||"ffmpeg"!==N)return;let e=window.setInterval(()=>{F.current||Q()},8e3);return()=>clearInterval(e)},[r,Z,Q,N]),(0,_.useEffect)(()=>{"ffmpeg"===N&&r&&Q()},[N,r,Q]);let ee=(0,_.useCallback)(async()=>{if(r){C(!0);try{var e;let t=await h("/tiktok_replay/list?process=".concat(encodeURIComponent(r)));z(null!==(e=t.files)&&void 0!==e?e:[])}catch(e){f(e.message),z([])}finally{C(!1)}}},[r,h,f]);(0,_.useEffect)(()=>{"replay"===N&&r&&ee()},[N,r,ee]),(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(eN);e&&q(JSON.parse(e))}catch(e){}try{G(window.localStorage.getItem(ej)||"")}catch(e){}},[]);let et=(0,_.useCallback)(e=>{q(e);try{window.localStorage.setItem(eN,JSON.stringify(e))}catch(e){}},[]),es=e=>{G(e);try{window.localStorage.setItem(ej,e)}catch(e){}},en=async()=>{if(r){A(!0),K(null),F.current=!1;try{var e;let t=new URLSearchParams({process:r,_ts:String(Date.now())}),n=await h("/get_url_config?".concat(t));X(null!==(e=n.content)&&void 0!==e?e:""),K(s("已从服务器读取 URL_config","Reloaded URL_config from server"))}catch(e){K(e.message)}finally{A(!1)}}},el=async()=>{try{await Promise.resolve(x(W.current)),F.current=!1}catch(e){}},ei=async e=>{if(r){P(!0);try{await h("/tiktok_replay/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({process:r,filename:e})}),f(s("已删除文件","File removed")),await ee()}catch(e){f(e.message)}finally{P(!1)}}},er=async e=>{var t;let n=null===(t=e.target.files)||void 0===t?void 0:t[0];if(e.target.value="",n&&r){P(!0);try{let e=new FormData;e.append("file",n);let t=await (0,Y.N)("".concat(p,"/tiktok_replay/upload?process=").concat(encodeURIComponent(r)),{method:"POST",body:e});f(t.message||s("上传成功","Uploaded")),await ee()}catch(e){f(e.message)}finally{P(!1)}}},ex=l||I||R,em=ew.find(e=>e.id===T),eh=!!(null==g?void 0:g.can_stream_hdmi),ep=(null==g?void 0:g.preferred_device)||(null==g?void 0:null===(t=g.video_devices)||void 0===t?void 0:t[0])||"";return(0,n.jsxs)("div",{className:"mx-auto max-w-4xl space-y-6",children:[v?(0,n.jsx)(eu,{t:s,title:s("TikTok HDMI 硬件链路","TikTok HDMI hardware chain"),subtitle:s("板端编码经 HDMI 到显示/下游设备;与「网络」页顶卡相同的箭头风格。","Encode on SoC → HDMI → display/downstream; same arrow style as Network header."),onNavigate:v,steps:[{label:"FFmpeg",sub:s("采集 / 推流","Capture"),gradient:"from-cyan-400 to-blue-500",target:"live_tiktok"},{label:"HDMI",sub:s("板载输出","SoC out"),gradient:"from-violet-500 to-fuchsia-500"},{label:"Android",sub:s("AOSP / 手机","AOSP"),gradient:"from-amber-400 to-orange-500",target:"android"}]}):null,(0,n.jsx)("div",{className:"rounded-2xl border border-cyan-500/25 bg-gradient-to-br from-cyan-500/[0.14] via-zinc-950/80 to-fuchsia-500/10 p-6 shadow-xl shadow-cyan-900/10",children:(0,n.jsx)("div",{className:"flex flex-wrap items-start gap-4",children:(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[(0,n.jsx)("div",{className:"flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-cyan-500/35 to-fuchsia-600/25 ring-1 ring-white/10",children:(0,n.jsx)(D.Z,{className:"h-5 w-5 text-cyan-200"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold tracking-tight text-white",children:s("TikTok 无人直播(单路)","TikTok unmanned (single lane)")}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-zinc-500",children:s("布局对齐 YouTube 单频道:直播开关 + 源站 + URL_config;无 stream key,输出走 HDMI 硬件链路。","Same layout as YouTube single: controls + URLs; no stream key — HDMI hardware path.")})]})]})})}),(0,n.jsx)("div",{className:"rounded-2xl border border-cyan-500/20 bg-cyan-500/[0.06] p-4 ring-1 ring-white/[0.04]",children:(0,n.jsx)("p",{className:"text-xs leading-relaxed text-cyan-100/90",children:s("HDMI 互斥:后端在「开始 / 重新开始」TikTok 或 obs*.sh(SRS 拉流上屏)时,会自动停止其它正在占用 HDMI 链路的同类进程;与 YouTube 推流互不干扰。","HDMI mutex: starting TikTok or obs*.sh stops other TikTok/OBS HDMI sinks; YouTube RTMP is unaffected.")})}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/10 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(ea.Z,{className:"h-4 w-4 text-cyan-300"}),s("X86 HDMI 采集状态","X86 HDMI capture status")]}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("这里直接显示主机是否识别到采集卡和 /dev/video 设备,可用于验证 ARM HDMI 进 X86 的链路。","Shows whether the host sees the capture card and /dev/video nodes for ARM-to-X86 HDMI ingest.")})]}),(0,n.jsx)("span",{className:"rounded-full px-3 py-1 text-[11px] font-semibold ring-1 ".concat(eh?"bg-emerald-500/20 text-emerald-200 ring-emerald-500/30":"bg-rose-500/15 text-rose-200 ring-rose-500/25"),children:eh?s("可推流","Ready"):s("未就绪","Not ready")})]}),(0,n.jsxs)("div",{className:"mt-4 grid gap-3 md:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/25 p-4 text-[11px] text-zinc-400",children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"device: "}),(0,n.jsx)("span",{className:"font-mono text-zinc-200",children:ep||"—"})]}),(0,n.jsxs)("p",{className:"mt-2",children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"video nodes: "}),(0,n.jsx)("span",{className:"font-mono text-zinc-200",children:((null==g?void 0:g.video_devices)||[]).join(", ")||"—"})]}),(0,n.jsxs)("p",{className:"mt-2",children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"usb matches: "}),(0,n.jsx)("span",{className:"text-zinc-300",children:((null==g?void 0:g.usb_capture_matches)||[]).length||0})]})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/25 p-4 text-[11px] text-zinc-400",children:[(0,n.jsx)("p",{className:"text-zinc-600",children:s("建议 FFmpeg","Suggested FFmpeg")}),(0,n.jsx)("p",{className:"mt-2 break-all font-mono text-zinc-200",children:(null==g?void 0:g.suggested_ffmpeg_cmd)||"—"}),(null==g?void 0:g.suggested_ffmpeg_cmd)?(0,n.jsxs)("button",{type:"button",onClick:()=>m(g.suggested_ffmpeg_cmd||""),className:"mt-3 inline-flex items-center gap-2 rounded-lg bg-cyan-500/15 px-3 py-2 text-xs font-medium text-cyan-100 ring-1 ring-cyan-500/25",children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),s("复制命令","Copy command")]}):null]})]}),((null==g?void 0:g.issues)||[]).length?(0,n.jsx)("ul",{className:"mt-4 list-inside list-disc space-y-1 text-[11px] text-amber-200/85",children:((null==g?void 0:g.issues)||[]).map(e=>(0,n.jsx)("li",{children:e},e))}):null]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-amber-500/20 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-amber-200/90",children:[(0,n.jsx)(B.Z,{className:"h-4 w-4"}),(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:s("直播开关","Live control")})]}),(0,n.jsx)("label",{className:"mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500",children:s("TikTok 进程(PM2)","TikTok PM2 process")}),(0,n.jsx)("select",{className:"mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white",value:r,onChange:e=>a(e.target.value),children:w.map(e=>(0,n.jsxs)("option",{value:e.pm2,children:[e.label," (",e.pm2,")"]},e.pm2))}),(0,n.jsx)("label",{className:"mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500",children:s("直播源","Video source")}),(0,n.jsxs)("select",{className:"mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white",value:N,onChange:e=>$(e.target.value),children:[(0,n.jsx)("option",{value:"ffmpeg",hidden:!0,children:"FFmpeg(抖音 / TikTok 等直播间 URL)"}),(0,n.jsx)("option",{value:"replay",hidden:!0,children:s("录播素材(本地上传)","VOD upload")}),(0,n.jsx)("option",{value:"srs",children:s("SRS(OBS 推流)","SRS (OBS)")})]}),"srs"===N?(0,n.jsx)("p",{className:"mt-2 text-[11px] leading-relaxed text-amber-200/85",children:s("此模式不显示 URL_config:请在 OBS 中填写下方 RTMP 推流地址;板端 SRS 拉流上屏仍可能占用 HDMI,与 TikTok 进程互斥规则不变。","URL_config is hidden: set the RTMP URL in OBS. SRS pull-to-HDMI may still mutex with TikTok per server rules.")}):null,(0,n.jsx)("div",{className:"mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3",children:[["start",s("开始直播","Start"),"bg-emerald-500/20 text-emerald-200 ring-emerald-500/30"],["stop",s("停止直播","Stop"),"bg-rose-500/15 text-rose-200 ring-rose-500/25"],["restart",s("重新开始","Restart"),"bg-amber-500/15 text-amber-200 ring-amber-500/25"]].map(e=>{let[t,s,l]=e;return(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>d(t),className:"rounded-xl px-4 py-3 text-sm font-medium ring-1 ".concat(l),children:s},t)})}),(0,n.jsxs)("p",{className:"mt-3 text-center text-[11px] text-zinc-500",children:[s("当前 HDMI 预设(备忘)","HDMI preset (memo)"),":"," ",(0,n.jsx)("span",{className:"font-mono text-cyan-300/90",children:em?s(em.labelZh,em.labelEn):T})]})]}),"replay"===N?(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/25 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(eo.Z,{className:"h-4 w-4 text-violet-300"}),s("录播素材","VOD library")]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsxs)("label",{className:"inline-flex cursor-pointer items-center gap-2 rounded-xl bg-violet-500/15 px-3 py-2 text-xs font-medium text-violet-100 ring-1 ring-violet-500/30",children:[(0,n.jsx)(ec.Z,{className:"h-3.5 w-3.5"}),(0,n.jsx)("span",{children:s("上传视频","Upload")}),(0,n.jsx)("input",{type:"file",accept:".mp4,.mkv,.ts,.flv,.mov,.m4v,.webm",className:"hidden",onChange:er})]}),(0,n.jsx)("button",{type:"button",disabled:ex||!r,onClick:()=>void ee(),className:"rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-xs text-zinc-300",children:s("刷新列表","Refresh")})]})]}),(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:s("文件保存在服务器 config/tiktok_replay/对应进程目录;点「开始直播」会写入 replayfile 行并启动 PM2 进程。停播请用上方「停止直播」。","Files under config/tiktok_replay/. Go live writes replayfile + starts PM2. Use Stop above to stop.")}),S?(0,n.jsx)("p",{className:"mt-4 text-xs text-zinc-500",children:s("加载中…","Loading…")}):0===k.length?(0,n.jsx)("p",{className:"mt-4 text-xs text-zinc-500",children:s("暂无文件,请先上传。","No files yet.")}):(0,n.jsx)("ul",{className:"mt-4 space-y-2",children:k.map(e=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center justify-between gap-2 rounded-xl border border-white/10 bg-black/30 px-3 py-2 text-xs text-zinc-300",children:[(0,n.jsx)("span",{className:"min-w-0 flex-1 truncate font-mono",children:e.name}),(0,n.jsxs)("span",{className:"shrink-0 text-zinc-500",children:[(e.size/1048576).toFixed(1)," MB"]}),(0,n.jsxs)("div",{className:"flex shrink-0 flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>void(async()=>{try{await Promise.resolve(u(e.replay_url,e.name))}catch(e){}})(),className:"rounded-lg bg-emerald-500/20 px-2 py-1 text-[11px] text-emerald-100 ring-1 ring-emerald-500/30",children:s("开始直播","Go live")}),(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>d("stop"),className:"rounded-lg bg-rose-500/15 px-2 py-1 text-[11px] text-rose-100 ring-1 ring-rose-500/25",children:s("停播","Stop")}),(0,n.jsxs)("button",{type:"button",disabled:ex,onClick:()=>void ei(e.name),className:"inline-flex items-center gap-1 rounded-lg bg-zinc-700/40 px-2 py-1 text-[11px] text-zinc-200",children:[(0,n.jsx)(ed.Z,{className:"h-3 w-3"}),s("删除","Del")]})]})]},e.name))})]}):null,"srs"===N?(0,n.jsxs)("div",{className:"rounded-2xl border border-emerald-500/25 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:s("SRS / OBS 推流","SRS / OBS ingest")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("OBS:设置 → 推流 → 服务选「自定义」,服务器填 RTMP 地址;串流密钥可与 SRS 应用配置一致(默认 live/livestream)。","OBS → Stream → Custom: RTMP URL as server; stream key per SRS app (default live/livestream).")}),(0,n.jsxs)("dl",{className:"mt-4 space-y-3 text-xs",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-500",children:s("RTMP 推流地址(OBS 服务器)","RTMP publish URL")}),(0,n.jsxs)("dd",{className:"mt-1 flex flex-wrap items-center gap-2 font-mono text-emerald-200/90",children:[(0,n.jsx)("span",{className:"break-all",children:b.srs_rtmp_publish||"—"}),b.srs_rtmp_publish?(0,n.jsx)("button",{type:"button",className:"shrink-0 text-cyan-300 hover:text-cyan-200",onClick:()=>m(b.srs_rtmp_publish),children:(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"})}):null]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-500",children:s("HTTP-FLV 预览","HTTP-FLV preview")}),(0,n.jsxs)("dd",{className:"mt-1 flex flex-wrap items-center gap-2 font-mono text-zinc-400",children:[(0,n.jsx)("span",{className:"break-all",children:b.srs_play_flv||b.srs_http||"—"}),b.srs_play_flv||b.srs_http?(0,n.jsx)("button",{type:"button",className:"shrink-0 text-cyan-300 hover:text-cyan-200",onClick:()=>m(b.srs_play_flv||b.srs_http),children:(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"})}):null]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-500",children:s("SRS 控制台","SRS web UI")}),(0,n.jsx)("dd",{className:"mt-1 font-mono text-zinc-400",children:(0,n.jsx)("a",{href:b.srs_http||"#",target:"_blank",rel:"noreferrer",className:"text-cyan-300 hover:underline",children:b.srs_http||"—"})})]})]})]}):null,(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(ea.Z,{className:"h-4 w-4 text-cyan-400"}),s("HDMI 硬件与时序","HDMI timing")]}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("点选一路作为现场备忘;与板端 ffmpeg/OBS 采集参数对齐。","Pick a preset as field memo; match capture settings.")}),(0,n.jsx)("div",{className:"mt-4 grid gap-3 md:grid-cols-3",children:ew.map(e=>{let t=L===e.id,l=T===e.id;return(0,n.jsxs)("button",{type:"button",onClick:()=>{M(t?null:e.id),E(e.id)},className:"rounded-2xl border p-4 text-left transition ".concat(l?"border-cyan-500/50 ring-1 ring-cyan-500/20":""," ").concat(t?"border-cyan-500/40 bg-cyan-500/10":"border-white/[0.08] bg-zinc-950/50 hover:border-white/15"),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(ea.Z,{className:"h-4 w-4 text-cyan-400"}),s(e.labelZh,e.labelEn)]}),(0,n.jsx)("p",{className:"mt-2 font-mono text-[11px] text-zinc-400",children:e.spec}),t?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:s(e.hintZh,e.hintEn)}):null]},e.id)})}),(0,n.jsxs)("div",{className:"mt-6 rounded-xl border border-white/5 bg-black/25 p-4",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-zinc-400",children:s("上线前检查清单(本地保存)","Pre-flight checklist (local)")}),(0,n.jsx)("ul",{className:"mt-3 space-y-2",children:[{id:"cable",zh:"HDMI 线材插紧、方向正确(如需转接头确认规格)",en:"HDMI cable seated; adapter specs OK"},{id:"thermal",zh:"长时间推流注意散热,过热会掉帧黑屏",en:"Thermal headroom for long runs"}].map(e=>(0,n.jsxs)("li",{className:"flex items-start gap-2 text-xs text-zinc-400",children:[(0,n.jsx)("input",{type:"checkbox",className:"mt-0.5 rounded border-white/20 bg-black/40",checked:!!V[e.id],onChange:t=>et({...V,[e.id]:t.target.checked})}),(0,n.jsx)("span",{children:s(e.zh,e.en)})]},e.id))}),(0,n.jsx)("label",{className:"mt-4 block text-[11px] text-zinc-500",children:s("HDMI / 走线备忘","HDMI / wiring notes")}),(0,n.jsx)("textarea",{className:"mt-1 min-h-[72px] w-full resize-y rounded-lg border border-white/10 bg-black/40 p-3 text-xs text-zinc-300",value:J,onChange:e=>es(e.target.value),spellCheck:!1,placeholder:s("接口、线长、显示器型号…","Ports, cable length, display model…")})]})]}),"ffmpeg"===N?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:s("直播地址列表 \xb7 URL_config.ini","URL_config.ini")}),(0,n.jsxs)("button",{type:"button",className:"inline-flex items-center gap-1 text-xs text-cyan-300 hover:text-cyan-200",onClick:()=>m(o),children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),s("复制全文","Copy all")]})]}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("一行一个地址;可勾选自动从服务器刷新,或点「重新读取」手动同步。","One URL per line; enable auto-refresh or reload from server.")}),(0,n.jsx)("div",{className:"mt-2 flex flex-wrap items-center gap-4 text-xs text-zinc-400",children:(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:Z,onChange:e=>O(e.target.checked)}),s("每 8 秒自动从服务器刷新","Auto-refresh from server every 8s")]})}),H?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:H}):null,(0,n.jsx)("textarea",{className:"mt-4 min-h-[200px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300",value:o,onChange:e=>{F.current=!0,X(e.target.value)},spellCheck:!1}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>void en(),className:"rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-300",children:s("重新读取","Reload from server")}),(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>void el(),className:"rounded-xl bg-cyan-500/20 px-4 py-2 text-sm font-medium text-cyan-100 ring-1 ring-cyan-500/30",children:s("保存 URL 配置","Save URL config")})]})]}):null,(0,n.jsx)(ev,{t:s,currentProc:r,fetchJson:h,urlListText:"ffmpeg"===N?o:"",keySuffixUi:"",showKeyRow:!1})]})}var eS=s(5468),e_=s(9397),eC=s(90);let eR="live-hub-youtube-pro-v2",eP=/[^a-zA-Z0-9_.-]+/g;function eL(e){return(e||"").trim().replace(eP,"_")}function eM(e){return eL(String(e.pm2Name||""))||eO(String(e.id||""))}function eT(e){if(!e||"object"!=typeof e)return null;let t=String(e.id||"").trim();if(!t)return null;let s=String(e.name||"").trim()||t;return{id:t,name:s,streamKeySuffix:"string"==typeof e.streamKeySuffix?e.streamKeySuffix:void 0,streamKey:"string"==typeof e.streamKey?e.streamKey:void 0,urlLines:"string"==typeof e.urlLines?e.urlLines:void 0,pm2Name:"string"==typeof e.pm2Name?e.pm2Name:void 0,notes:"string"==typeof e.notes?e.notes:void 0}}function eU(e){if(!e)return[];try{let t=JSON.parse(e);if(!Array.isArray(t))return[];return t.map(e=>eT(e)).filter(e=>null!==e)}catch(e){return[]}}function eE(e){window.localStorage.setItem(eR,JSON.stringify(e))}let eI=["/hub/youtube_pro_channels","/youtube_pro_channels"];async function eD(e){for(let s of eI)try{var t;let n=await e(s);return{fetched:!0,channels:(t=n.channels,Array.isArray(t)?t.map(e=>eT(e)).filter(e=>null!==e):[])}}catch(e){}return{fetched:!1,channels:[]}}async function eA(e,t){let s=null;for(let n of eI)try{await e(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({channels:t})});return}catch(e){s=e instanceof Error?e:Error(String(e))}throw null!=s?s:Error("youtube_pro_channels sync failed")}function eZ(){return"ch_".concat(Date.now().toString(36),"_").concat(Math.random().toString(36).slice(2,7))}function eO(e){return"youtube2__".concat(eL(e)||"channel")}function eH(e){return/youtube/i.test(e.script)||/youtube/i.test(e.pm2)}function eB(e){return(e.split("/").pop()||e).replace(/\.[^.]+$/,"")}function eK(e){return eH(e)&&e.pm2.trim()===eB(e.script).trim()}function eF(e){var t;return!!e&&(/youtube/i.test(e.pm2)||/youtube/i.test(null!==(t=e.script)&&void 0!==t?t:""))}function eW(e,t){let s=((null==t?void 0:t.business_status)||"").trim().toLowerCase();return(null==t?void 0:t.is_pushing)||"streaming"===s?0:eV(null==t?void 0:t.process_status)?1:"youtube"===e.pm2.trim().toLowerCase()?2:"youtube"===eB(e.script).trim().toLowerCase()?3:10}let eY="live-hub-youtube-mode-v1",eJ=new Set(["tiktok","obs","web"]);function eG(e){var t,s,n;return{name:e.name,streamKey:null!==(t=e.streamKey)&&void 0!==t?t:"",pm2Name:null!==(s=e.pm2Name)&&void 0!==s?s:eO(e.id),notes:null!==(n=e.notes)&&void 0!==n?n:""}}function eV(e){return/^(online|running)$/i.test((e||"").trim())}function eq(e,t){let s=((null==e?void 0:e.business_status)||"").trim().toLowerCase();return"ready"===s?t("已配置","Ready"):"streaming"===s?t("推流中","Pushing"):"waiting_source"===s?t("等待上游","Waiting source"):"source_live"===s?t("源已开播,转推未起","Source live, relay down"):"monitoring"===s?t("监控中","Monitoring"):"misconfigured"===s?t("密钥异常","Key invalid"):"stale"===s?t("心跳过期","Stale"):"error"===s?t("异常","Error"):eV(null==e?void 0:e.process_status)?t("运行中","Running"):((null==e?void 0:e.process_status)||"").trim()||t("未运行","Idle")}function eX(e){return e.split(/\r?\n/).map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"))}function e$(e,t){return eX(e).length>0&&0===eX(t).length}function eQ(e){let{kind:t,busyKind:s,targetPm2:l,busy:i,online:r,label:a,className:o,baseLock:c,onRun:d,notify:x,t:u,compact:m}=e,h=function(e){if(!(null==e?void 0:e.startsWith("proc:")))return null;let t=e.slice(5),s=t.indexOf(":");if(s<=0)return null;let n=t.slice(0,s),l=t.slice(s+1);return l&&["start","stop","restart"].includes(n)?{action:n,pm2:l}:null}(i),p=h&&h.pm2===l,b=null!=s?s:t,g=!!(p&&h.action===b),f=!!(p&&h.action!==b),y="start"===t&&r,w="stop"===t&&!r,N="restart"===t&&!r,j=y||w||N;return(0,n.jsxs)("button",{type:"button",onClick:()=>{if(!g){if(f){x(u("请等待当前操作完成","Wait for the current action to finish"));return}if(y){x(u("已在直播中,无需重复开始","Already live"));return}if(w){x(u("当前未在直播,无法停止","Not live — cannot stop"));return}if(N){x(u("进程未运行时请使用「开始直播」","Use Start when the process is not running"));return}c||d()}},className:"relative overflow-hidden rounded-xl ring-1 transition ".concat(m?"min-h-[2rem] px-3 py-1.5 text-xs font-medium":"min-h-[2.75rem] px-4 py-3 text-sm font-medium"," ").concat(o," ").concat(j||c||g||f?"cursor-not-allowed":""," ").concat(j&&!g?"opacity-45":""," ").concat(f?"opacity-35":""," ").concat(g?"ring-violet-400/40":""),children:[g?(0,n.jsx)("span",{className:"absolute inset-0 flex items-center justify-center bg-black/25 backdrop-blur-[2px]",children:(0,n.jsx)(v.Z,{className:"".concat(m?"h-4 w-4":"h-6 w-6"," animate-spin text-white")})}):null,(0,n.jsxs)("span",{className:"inline-flex items-center justify-center gap-1.5 ".concat(g?"invisible":""),children:[j?(0,n.jsx)(eS.Z,{className:"".concat(m?"h-3 w-3":"h-4 w-4"," shrink-0 opacity-90"),"aria-hidden":!0}):null,a]})]})}function e0(e){var t,s,l,i,r;let{t:a,busy:o,entries:d,currentProc:x,setCurrentProc:u,urlConfig:m,setUrlConfig:h,onRunProcess:p,onSaveUrlConfig:b,fetchJson:g,liveProcesses:f,notify:w,onNavigate:N,quickLinks:j}=e,k=(0,_.useMemo)(()=>d.filter(eH),[d]),z=(0,_.useMemo)(()=>k.filter(e=>eK(e)),[k]),S=(0,_.useMemo)(()=>(function(e,t){let s=e.filter(eH),n=s.filter(e=>eK(e)),l=n.length?[...n]:s.length?[...s]:[...e],i=new Set(l.map(e=>e.pm2.trim()));for(let e of t.filter(eF)){var r,a,o,c;let t=e.pm2.trim();if(!t||i.has(t))continue;let n=(e.business_status||"").trim().toLowerCase();if(!e.is_pushing&&"streaming"!==n&&!eV(e.process_status))continue;let d=s.find(e=>e.pm2.trim()===t);l.push(null!=d?d:{pm2:t,script:null!==(o=null!==(a=e.script)&&void 0!==a?a:null===(r=s[0])||void 0===r?void 0:r.script)&&void 0!==o?o:"youtube.py",label:null!==(c=e.label)&&void 0!==c?c:t}),i.add(t)}return l})(k.length?k:d,f),[d,f,k]),C=(0,_.useMemo)(()=>(function(e,t){if(!e.length)return"";let s=new Map(t.filter(eF).map(e=>[e.pm2.trim(),e])),n=e[0],l=eW(n,s.get(n.pm2.trim()));for(let t of e.slice(1)){let e=eW(t,s.get(t.pm2.trim()));e"youtube"===e.pm2.trim().toLowerCase());if(n)return n.pm2;let l=e.find(e=>"youtube"===eB(e.script).trim().toLowerCase());return l?l.pm2:null!==(s=null===(t=e[0])||void 0===t?void 0:t.pm2)&&void 0!==s?s:""}(S),[f,S]),[R,P]=(0,_.useState)("single"),[L,M]=(0,_.useState)([]),[T,U]=(0,_.useState)(""),[E,I]=(0,_.useState)(""),[D,A]=(0,_.useState)({key:"",rtmps:!0,bitrate:"",fastAudio:!1}),[O,H]=(0,_.useState)(null),[K,F]=(0,_.useState)(!1),[W,Y]=(0,_.useState)(""),[J,G]=(0,_.useState)(!0),[V,q]=(0,_.useState)(!1),[X,$]=(0,_.useState)(!1),[Q,ee]=(0,_.useState)(null),[et,es]=(0,_.useState)({}),[en,el]=(0,_.useState)(!1),[ei,er]=(0,_.useState)(null),[ea,eo]=(0,_.useState)(0),ec=(0,_.useRef)(!1),ef=(0,_.useRef)(m),ey=(0,_.useRef)(W),ew=(0,_.useRef)(x),eN=(0,_.useRef)(0),ej=(0,_.useRef)(0),ek=(0,_.useCallback)(e=>{ef.current=e,h(e)},[h]),ez=(0,_.useCallback)(e=>{ey.current=e,Y(e)},[]);(0,_.useEffect)(()=>{ec.current=!1},[x]),(0,_.useEffect)(()=>{ew.current=x},[x]),(0,_.useEffect)(()=>{ef.current=m},[m]),(0,_.useEffect)(()=>{ey.current=W},[W]);let eS=(0,_.useCallback)(async()=>{let e=ew.current.trim();if(!e)return;let t=++eN.current;try{var s,n,l;let i=new URLSearchParams({process:e,_ts:String(Date.now())}),r=await g("/get_url_config?".concat(i));if(t!==eN.current||e!==ew.current.trim())return;let a=null!==(s=r.content)&&void 0!==s?s:"";if(ec.current)return;if("single"===R)ek(a);else{let e=null!==(l=null===(n=L.find(e=>e.id===T))||void 0===n?void 0:n.urlLines)&&void 0!==l?l:"";if(e$(e,a)){ez(e);return}ez(a),T&&M(e=>{let t=e.map(e=>e.id===T?{...e,urlLines:a}:e);return eE(t),t})}}catch(e){}},[T,ez,ek,L,g,R]);(0,_.useEffect)(()=>{if(!x||!J)return;let e=window.setInterval(()=>{ec.current||eS()},8e3);return()=>clearInterval(e)},[x,J,eS]);let eP=async()=>{let e=ew.current.trim();if(!e)return;q(!0),ee(null),ec.current=!1;let t=++eN.current;try{var s,n,l;let i=new URLSearchParams({process:e,_ts:String(Date.now())}),r=await g("/get_url_config?".concat(i));if(t!==eN.current||e!==ew.current.trim())return;let o=null!==(s=r.content)&&void 0!==s?s:"";if(ec.current){ee(a("检测到本地未保存修改,已保留当前草稿","Kept the local unsaved draft"));return}if("single"===R)ek(o);else{let e=null!==(l=null===(n=L.find(e=>e.id===T))||void 0===n?void 0:n.urlLines)&&void 0!==l?l:"";if(e$(e,o)){ez(e),ee(a("服务器暂无已保存 URL,已保留本地草稿","Server has no saved URLs, kept the local draft"));return}ez(o),T&&M(e=>{let t=e.map(e=>e.id===T?{...e,urlLines:o}:e);return eE(t),t})}ee(a("已从服务器读取 URL_config","Reloaded URL_config from server"))}catch(s){if(t!==eN.current||e!==ew.current.trim())return;ee(s.message)}finally{t===eN.current&&e===ew.current.trim()&&q(!1)}};(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(eY);("pro"===e||"single"===e)&&P(e)}catch(e){}},[]),(0,_.useEffect)(()=>{let e=!1;return(async()=>{try{let t=await eD(g);if(t.fetched&&t.channels.length&&!e){M(t.channels),eE(t.channels);return}}catch(e){}if(e)return;let t=function(){let e=window.localStorage.getItem(eR);if(!e&&(e=window.localStorage.getItem("live-hub-youtube-pro-v1"))){let t=eU(e);if(t.length)return window.localStorage.setItem(eR,JSON.stringify(t)),t}return eU(e)}(),s=t.length>0?t:(()=>{let e=eZ();return[{id:e,name:"线路 1",streamKey:"",urlLines:"",pm2Name:eO(e),notes:""}]})();M(s),t.length||eE(s)})(),()=>{e=!0}},[g]),(0,_.useEffect)(()=>{if(!L.length){T&&U("");return}T&&L.some(e=>e.id===T)||U(L[0].id)},[L,T]);let eT=(0,_.useCallback)(e=>f.find(t=>t.pm2===e),[f]),eI=(0,_.useCallback)(e=>{var t;return null===(t=eT(e))||void 0===t?void 0:t.process_status},[eT]),e0=eT(x),e1=(0,_.useMemo)(()=>{var e,t;return!!x&&(/youtube/i.test(x)||/youtube/i.test(null!==(e=null==e0?void 0:e0.script)&&void 0!==e?e:"")||/youtube/i.test(null!==(t=null==e0?void 0:e0.label)&&void 0!==t?t:""))},[x,e0]);(0,_.useEffect)(()=>{"single"!==R||!C||x&&e1||u(C)},[x,e1,R,C,u]);let e5=(0,_.useCallback)(e=>{M(e),eE(e)},[]),e2=(0,_.useCallback)(async e=>{await eA(g,e)},[g]),e3=(0,_.useCallback)(e=>{e5(e),e2(e).catch(e=>{w("".concat(a("多频道列表未同步到服务器","Channel list not saved on server"),": ").concat(e.message))})},[e5,w,e2,a]),e4=L.find(e=>e.id===T)||L[0],e6=(0,_.useMemo)(()=>{var e;return e4?null!==(e=et[e4.id])&&void 0!==e?e:eG(e4):null},[e4,et]);(0,_.useEffect)(()=>{e4&&es(e=>e[e4.id]?e:{...e,[e4.id]:eG(e4)})},[e4]),(0,_.useEffect)(()=>{er(null)},[T]);let e8=(0,_.useCallback)((e,t)=>{e4&&(es(s=>{var n;return{...s,[e4.id]:{...null!==(n=s[e4.id])&&void 0!==n?n:eG(e4),[e]:t}}}),er(null))},[e4]),e9=e4?eM(e4):"",e7=e4&&e6?eM({id:e4.id,pm2Name:e6.pm2Name}):"",te=!!e4&&!!e6&&e7!==e9,tt=(0,_.useMemo)(()=>{if(!e4||!e6)return{ok:!1,message:a("请选择线路","Pick a lane"),normalizedName:"",normalizedPm2:"",normalizedStreamKey:"",normalizedNotes:""};let e=e6.name.trim()||"".concat(a("线路","Ch")," ").concat(L.findIndex(e=>e.id===e4.id)+1),t=eM({id:e4.id,pm2Name:e6.pm2Name});return t?eJ.has(t)?{ok:!1,message:a("该进程名保留给系统模块,请换一个","This PM2 name is reserved"),normalizedName:e,normalizedPm2:t,normalizedStreamKey:e6.streamKey.trim(),normalizedNotes:e6.notes.trim()}:L.find(e=>e.id!==e4.id&&eM(e)===t)?{ok:!1,message:a("该进程名已被其它线路占用","Another lane already uses this PM2 name"),normalizedName:e,normalizedPm2:t,normalizedStreamKey:e6.streamKey.trim(),normalizedNotes:e6.notes.trim()}:{ok:!0,message:"",normalizedName:e,normalizedPm2:t,normalizedStreamKey:e6.streamKey.trim(),normalizedNotes:e6.notes.trim()}:{ok:!1,message:a("进程名不能为空","PM2 name is required"),normalizedName:e,normalizedPm2:t,normalizedStreamKey:e6.streamKey.trim(),normalizedNotes:e6.notes.trim()}},[e4,e6,L,a]),ts=(0,_.useMemo)(()=>{if(!e4||!e6)return!1;let e=eG(e4);return e6.name!==e.name||e6.streamKey!==e.streamKey||eL(e6.pm2Name)!==eL(e.pm2Name)||e6.notes!==e.notes},[e4,e6]),tn=(0,_.useCallback)(e=>{var t,s,n;if("single"===e&&"pro"===R&&e4){let e=ey.current;e!==(null!==(t=e4.urlLines)&&void 0!==t?t:"").trim()&&e3(L.map(t=>t.id===e4.id?{...t,urlLines:e}:t))}if("pro"===e&&L.length){let e=L[0],t=ef.current.trim(),l=z.some(e=>e.pm2===x)&&x.trim()?x.trim():eM(e),i=[{...e,streamKey:D.key.trim()||e.streamKey||"",urlLines:t||e.urlLines||"",pm2Name:l},...L.slice(1)];e3(i);let r=null!==(s=i.find(e=>e.id===T))&&void 0!==s?s:i[0];ez((null!==(n=null==r?void 0:r.urlLines)&&void 0!==n?n:"").trim()||t)}P(e);try{window.localStorage.setItem(eY,e)}catch(e){}},[R,e4,L,ez,D.key,x,z,T,e3]),tl=(0,_.useCallback)(e=>{var t,s;let n=ey.current;e4&&"pro"===R&&n!==(null!==(t=e4.urlLines)&&void 0!==t?t:"").trim()&&e3(L.map(e=>e.id===e4.id?{...e,urlLines:n}:e)),ez((null!==(s=e.urlLines)&&void 0!==s?s:"").trim()),U(e.id),u(eM(e))},[e4,ez,R,L,u,e3]);(0,_.useEffect)(()=>{if("pro"!==R||!T)return;let e=L.find(e=>e.id===T);e&&u(eM(e))},[R,T,L,u]);let ti=(0,_.useCallback)(async()=>{let e=ew.current.trim();if(!e)return;let t=++ej.current;F(!0),H(null);try{var s;let n=new URLSearchParams({process:e,_ts:String(Date.now())}),l=await g("/get_config?".concat(n));if(t!==ej.current||e!==ew.current.trim())return;let i=null!==(s=l.content)&&void 0!==s?s:"";I(i),A(ep(i))}catch(s){if(t!==ej.current||e!==ew.current.trim())return;H(s.message)}finally{t===ej.current&&e===ew.current.trim()&&F(!1)}},[g]);(0,_.useEffect)(()=>{x&&(eS(),ti(),eo(e=>e+1))},[T,x,ti,R,eS]);let tr=(0,_.useCallback)(async()=>{var e;if(!e4||!e6)throw Error(a("请选择线路","Pick a lane"));if(!tt.ok)throw Error(tt.message);let t=ey.current,s=L.map(e=>e.id===e4.id?{...e,name:tt.normalizedName,streamKey:tt.normalizedStreamKey,pm2Name:tt.normalizedPm2,notes:tt.normalizedNotes,urlLines:t}:e);return e5(s),await e2(s),es(e=>({...e,[e4.id]:{name:tt.normalizedName,streamKey:tt.normalizedStreamKey,pm2Name:tt.normalizedPm2,notes:tt.normalizedNotes}})),{next:s,savedLane:null!==(e=s.find(e=>e.id===e4.id))&&void 0!==e?e:{...e4,name:tt.normalizedName,streamKey:tt.normalizedStreamKey,pm2Name:tt.normalizedPm2,notes:tt.normalizedNotes,urlLines:t},pm2:tt.normalizedPm2}},[e4,e6,tt,e5,L,e2,a]),ta=(0,_.useCallback)(async()=>{if(e4){el(!0),er(null);try{let e=await tr();u(e.pm2),er(a("线路设置已保存","Lane settings saved"))}catch(t){let e=t.message;er(e),w(e)}finally{el(!1)}}},[e4,w,tr,u,a]),to=async function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:ew.current,s=t.trim();if(!s){H(a("请选择进程","Pick a process"));return}F(!0),H(null);try{let t=new URLSearchParams({process:s});await g("/save_config?".concat(t),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:e})}),I(e),H(a("youtube.ini 已保存","youtube.ini saved"))}catch(e){H(e.message)}finally{F(!1)}},tc=async()=>{let e=eg(D);await to(e)},td=async()=>{F(!0),H(null);try{var e,t;let s=E||eg(D),n=await g("/config_optimize",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({root:"app-config",path:(t=ew.current,"youtube.".concat(t.replace(/[^a-zA-Z0-9_.-]/g,"_"),".ini")),content:s,action:"youtube_balanced_preset"})}),l=null!==(e=n.content)&&void 0!==e?e:s;I(l),A(ep(l)),H(n.message||a("已应用 YouTube 预设","Applied YouTube preset"))}catch(e){H(e.message)}finally{F(!1)}},tx=(0,_.useMemo)(()=>{var e,t;if("single"===R)return em("key = ".concat(D.key));let s=null!==(t=null!==(e=null==e6?void 0:e6.streamKey)&&void 0!==e?e:null==e4?void 0:e4.streamKey)&&void 0!==t?t:"";return em("key = ".concat(s))},[R,D.key,null==e4?void 0:e4.streamKey,null==e6?void 0:e6.streamKey]),tu=async()=>{if(e4)try{el(!0),er(null),eN.current+=1;let e=ey.current,t=await tr();u(t.pm2),await Promise.resolve(b(e,t.pm2)),ec.current=!1,er(a("线路与地址已保存","Lane settings and URLs saved"))}catch(t){let e=t instanceof Error?t.message:String(t);er(e),w(e)}finally{el(!1)}},tm=async()=>{let e=ew.current.trim();if(!e){w(a("请选择进程","Pick a process"));return}try{eN.current+=1,await Promise.resolve(b(ef.current,e)),ec.current=!1}catch(e){}},th=async()=>{let e="single"===R?ef.current:ey.current;$(!0),ee(null);try{var t;let s=await g("/config_optimize",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({root:"app-config",path:eb(ew.current),content:e,action:"dedupe_urls"})}),n=null!==(t=s.content)&&void 0!==t?t:e;"single"===R?ek(n):ez(n),ec.current=!0,ee(s.message||a("已去重当前 URL 列表","Deduplicated current URL list"))}catch(e){ee(e.message)}finally{$(!1)}},tp=async()=>{if(!e4||!e6)return;let e=ep(E||eg(D)),t=eg({key:e6.streamKey.trim(),rtmps:e.rtmps,bitrate:e.bitrate,fastAudio:e.fastAudio});el(!0),er(null);try{let e=await tr();u(e.pm2),await to(t,e.pm2),er(a("线路设置与 youtube.ini 已保存","Lane settings and youtube.ini saved"))}catch(t){let e=t.message;er(e),w(e)}finally{el(!1)}},tb="single"===R?m:W,tg=(0,_.useMemo)(()=>eX(tb).length,[tb]),tf=(0,_.useMemo)(()=>eh(tb).length,[tb]),tv=(0,_.useMemo)(()=>(0,eC.O0)(j),[j]),ty=(0,_.useMemo)(()=>(0,eC.U_)(tv,"pro"===R&&e4?L.findIndex(e=>e.id===e4.id):0),[e4,L,R,tv]),tw=ty.link?(0,ex.p)(ty.link.url):(0,ex.p)("http://live.local:9200/"),tN=(0,_.useMemo)(()=>(0,eC.Tc)(tv),[tv]),tj=(0,_.useMemo)(()=>{var e;return[null===(e=ty.link)||void 0===e?void 0:e.url,null==j?void 0:j.chromium_remote_debug,null==j?void 0:j.srs_api].filter(e=>!!e)},[j,null===(t=ty.link)||void 0===t?void 0:t.url]),tk=(0,_.useCallback)(async e=>{let t=e4?eM(e4):"";return e4&&e===t?await tr():(e5(L),await e2(L),{next:L,savedLane:null!=e4?e4:null,pm2:e})},[e4,e5,L,tr,e2]),tz=(0,_.useCallback)(async(e,t)=>{let s=!!e4&&eM(e4)===t;if("stop"!==e){var n,l;let e=L,s=t;try{let n=await tk(t);e=n.next,s=n.pm2}catch(e){w("".concat(a("当前线路保存失败","Failed to save the active lane"),": ").concat(e.message));return}let i=e.find(e=>eM(e)===s),r=null!==(n=null==i?void 0:i.urlLines)&&void 0!==n?n:"";if(!(null!==(l=null==i?void 0:i.streamKey)&&void 0!==l?l:"").trim()){w(a("请先填写当前线路的推流密钥","Fill the stream key before starting"));return}if(!eX(r).length){w(a("请先填写当前线路的直播地址","Fill the source URLs before starting"));return}t=s}s&&u(t),p(e,t)},[e4,L,tk,w,p,u,a]),tS=!!o||K||V||X||en,t_=eV(eI(x)),tC=(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap items-center gap-4 text-xs text-zinc-400",children:[(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:J,onChange:e=>G(e.target.checked)}),a("每 8 秒自动从服务器刷新","Auto-refresh from server every 8s")]}),(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void eP(),className:"rounded-lg border border-white/10 px-3 py-1.5 text-zinc-200 hover:bg-white/5",children:a("手动重新读取","Reload from server")}),(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void th(),className:"rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-1.5 text-cyan-100 hover:bg-cyan-500/15",children:X?a("去重中...","Deduplicating..."):a("智能去重","Deduplicate")})]});return(0,n.jsxs)("div",{className:"mx-auto max-w-6xl space-y-6",children:[N?(0,n.jsx)(eu,{t:a,title:a("YouTube 转播链路","YouTube relay chain"),subtitle:a("与「网络」页相同风格的链路示意:代理 → 编码推流 → 浏览器侧操作工作室。","Same visual language as Network: proxy → encode → browser studio."),onNavigate:N,steps:[{label:"ShellCrash",sub:a("透明代理","Proxy"),gradient:"from-violet-500 to-fuchsia-500",target:"network"},{label:"FFmpeg",sub:a("推流 / 转码","Stream"),gradient:"from-cyan-400 to-blue-500",target:"live_youtube"},{label:"Neko",sub:ty.link?"".concat(a("Chromium 工作室","Chromium studio")," \xb7 ").concat(ty.link.label):a("Chromium 工作室","Chromium studio"),gradient:"from-emerald-400 to-teal-500",openUrl:tw}]}):null,(0,n.jsx)("div",{className:"rounded-2xl border border-violet-500/25 bg-gradient-to-br from-violet-500/[0.12] via-zinc-950/80 to-cyan-500/5 p-6 shadow-xl shadow-violet-900/10",children:(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-4",children:[(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[(0,n.jsx)("div",{className:"flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-red-500/30 to-violet-600/30 ring-1 ring-white/10",children:(0,n.jsx)(c.Z,{className:"h-5 w-5 text-red-200"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold tracking-tight text-white",children:a("YouTube 无人直播","YouTube unmanned live")}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-zinc-500",children:a("单路一条流;多路时每条线路独立保存自己的密钥、URL 列表和 PM2 任务。填好后保存,再点「开始」。Neko 浏览器仅作辅助工作室,不再阻塞推流。","Single lane or multi-lane: every lane keeps its own key, URL list, and PM2 task. Save, then Start. Neko is optional browser tooling and no longer blocks streaming.")})]})]}),(0,n.jsxs)("div",{className:"flex rounded-xl border border-white/10 bg-black/30 p-1 ".concat(""),"aria-hidden":!1,children:[(0,n.jsx)("button",{type:"button",onClick:()=>tn("single"),className:"rounded-lg px-4 py-2 text-xs font-medium transition ".concat("single"===R?"bg-violet-500/25 text-white":"text-zinc-500 hover:text-zinc-300"),children:a("单频道","Single")}),(0,n.jsx)("button",{type:"button",onClick:()=>tn("pro"),className:"rounded-lg px-4 py-2 text-xs font-medium transition ".concat("pro"===R?"bg-violet-500/25 text-white":"text-zinc-500 hover:text-zinc-300"),children:a("多频道 Pro","Multi Pro")})]})]})}),tj.length?(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[ty.link?(0,n.jsx)("a",{href:tw,target:"_blank",rel:"noreferrer",className:"rounded-lg border border-emerald-500/20 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-100 ring-1 ring-emerald-500/20",children:a("打开当前线路 Neko 工作室","Open lane Neko studio")}):null,tv.length>1?(0,n.jsx)("div",{className:"flex flex-wrap gap-2",children:tv.map(e=>{var t;return(0,n.jsxs)("a",{href:(0,ex.p)(e.url),target:"_blank",rel:"noreferrer",className:"rounded-lg border px-3 py-2 text-xs ring-1 ".concat((null===(t=ty.link)||void 0===t?void 0:t.id)===e.id?"border-emerald-400/30 bg-emerald-500/15 text-emerald-50 ring-emerald-400/25":"border-white/10 bg-white/5 text-zinc-200 ring-white/10"),children:[e.label,e.port?" :".concat(e.port):""]},e.key)})}):null,(null==j?void 0:j.chromium_remote_debug)?(0,n.jsx)("a",{href:(0,ex.p)(j.chromium_remote_debug),target:"_blank",rel:"noreferrer",className:"rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-2 text-xs text-cyan-100 ring-1 ring-cyan-500/20",children:a("打开 Chromium 调试","Open Chromium debug")}):null,(null==j?void 0:j.srs_api)?(0,n.jsx)("a",{href:(0,ex.p)(j.srs_api),target:"_blank",rel:"noreferrer",className:"rounded-lg border border-violet-500/20 bg-violet-500/10 px-3 py-2 text-xs text-violet-100 ring-1 ring-violet-500/20",children:a("打开 SRS API","Open SRS API")}):null]}):null,(0,n.jsxs)("div",{className:"rounded-2xl border border-amber-500/20 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-amber-200/90",children:[(0,n.jsx)(B.Z,{className:"h-4 w-4"}),(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("直播开关","Live control")})]}),"single"===R?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("label",{className:"mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500",children:a("转播任务","Relay task")}),(0,n.jsxs)("select",{className:"mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white",value:x,onChange:e=>{let t=e.target.value;ew.current=t,u(t)},children:[x&&!S.some(e=>e.pm2===x)?(0,n.jsxs)("option",{value:x,children:[x,e0?" (".concat(eq(e0,a),")"):""]}):null,S.map(e=>(0,n.jsxs)("option",{value:e.pm2,children:[function(e,t){let s=eB(e.script).toLowerCase();return s.startsWith("douyin_youtube")?t("抖音→YouTube","Douyin → YouTube"):s.startsWith("youtube")?t("YouTube","YouTube"):e.label}(e,a)," (",e.pm2,")"]},e.pm2))]}),(0,n.jsxs)("div",{className:"mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3",children:[(0,n.jsx)(eQ,{kind:"start",targetPm2:x,busy:o,online:t_,label:a("开始直播","Start"),className:"bg-emerald-500/20 text-emerald-200 ring-emerald-500/30",baseLock:!1,onRun:()=>p("start",x),notify:w,t:a}),(0,n.jsx)(eQ,{kind:"stop",targetPm2:x,busy:o,online:t_,label:a("停止直播","Stop"),className:"bg-rose-500/15 text-rose-200 ring-rose-500/25",baseLock:!1,onRun:()=>p("stop",x),notify:w,t:a}),(0,n.jsx)(eQ,{kind:"restart",targetPm2:x,busy:o,online:t_,label:a("重新开始","Restart"),className:"bg-amber-500/15 text-amber-200 ring-amber-500/25",baseLock:!1,onRun:()=>p("restart",x),notify:w,t:a})]}),(0,n.jsxs)("p",{className:"mt-3 text-center text-xs text-zinc-400",children:[a("当前状态","Current state"),": ",eq(e0,a)]}),(0,n.jsxs)("p",{className:"mt-3 text-center font-mono text-[11px] text-zinc-600",children:["key ",a("尾码","suffix"),": ",tx||"—"]})]}):(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("div",{className:"mt-4 rounded-xl border border-cyan-500/25 bg-gradient-to-br from-cyan-500/[0.1] via-zinc-950/50 to-violet-500/[0.06] p-4 ring-1 ring-white/[0.04]",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-cyan-200/90",children:a("Pro 转播实况","Pro relay status")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:a("对齐桌面端:每路独立 URL / youtube 配置文件;点左侧信息切换编辑,右侧控制进程。","Per-lane config files like desktop; click row info to edit, use right-side controls for PM2.")}),tN?(0,n.jsxs)("p",{className:"mt-2 text-[11px] text-zinc-500",children:[a("Neko 实例","Neko instances"),": ",tN]}):null,(0,n.jsx)("div",{className:"mt-3 max-h-[min(24rem,55vh)] space-y-2 overflow-y-auto pr-1",children:L.map(e=>{var t,s,l;let i=eM(e),r=eT(i),c=eI(i),d=eX((null!==(t=e.urlLines)&&void 0!==t?t:"").trim()),x=eh((null!==(s=e.urlLines)&&void 0!==s?s:"").trim()),u=x[0],m=em("key = ".concat(null!==(l=e.streamKey)&&void 0!==l?l:"")),h=T===e.id,p=eV(c),b=L.findIndex(t=>t.id===e.id),g=(0,eC.U_)(tv,b).link;return(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2 rounded-lg border px-3 py-2.5 text-left text-xs transition sm:flex-nowrap ".concat(h?"border-violet-500/45 bg-violet-500/[0.1]":"border-white/10 bg-black/30 hover:border-white/18"),children:[(0,n.jsxs)("button",{type:"button",className:"min-w-0 flex-1 text-left",onClick:()=>{ew.current=eM(e),tl(e)},children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsx)("span",{className:"font-medium text-zinc-100",children:e.name}),(0,n.jsx)("span",{className:"shrink-0 rounded-md px-2 py-0.5 text-[10px] font-medium ring-1 ".concat(function(e){let t=((null==e?void 0:e.business_status)||"").trim().toLowerCase();return"ready"===t?"bg-sky-500/15 text-sky-100 ring-sky-500/25":"streaming"===t?"bg-emerald-500/15 text-emerald-200 ring-emerald-500/30":"waiting_source"===t||"monitoring"===t?"bg-amber-500/15 text-amber-100 ring-amber-500/25":"source_live"===t?"bg-sky-500/15 text-sky-100 ring-sky-500/25":"misconfigured"===t||"error"===t||"stale"===t?"bg-rose-500/15 text-rose-100 ring-rose-500/25":eV(null==e?void 0:e.process_status)?"bg-emerald-500/15 text-emerald-200 ring-emerald-500/30":"bg-zinc-600/20 text-zinc-400 ring-zinc-500/25"}(r)),children:eq(r,a)}),g?(0,n.jsx)("span",{className:"shrink-0 rounded-md bg-emerald-500/15 px-2 py-0.5 text-[10px] font-medium text-emerald-100 ring-1 ring-emerald-500/25",children:g.label}):null]}),(0,n.jsxs)("div",{className:"mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 font-mono text-[10px] text-zinc-500",children:[(0,n.jsxs)("span",{children:["key …",m||"—"]}),(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"}),(0,n.jsx)("span",{className:"truncate",title:i,children:i}),(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"}),(0,n.jsxs)("span",{children:["URL ",d.length]}),(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"}),(0,n.jsxs)("span",{children:["DY ",x.length]})]}),u?(0,n.jsx)("a",{href:u,target:"_blank",rel:"noreferrer",className:"mt-1 block max-w-full truncate text-cyan-300/90 underline-offset-2 hover:underline",onClick:e=>e.stopPropagation(),title:u,children:u.replace(/^https?:\/\//,"")}):(0,n.jsx)("span",{className:"mt-1 block text-zinc-600",children:"—"})]}),(0,n.jsxs)("div",{className:"flex w-full shrink-0 flex-wrap items-center justify-end gap-1.5 sm:w-auto",onClick:e=>e.stopPropagation(),onKeyDown:e=>e.stopPropagation(),children:[(0,n.jsx)(eQ,{kind:"start",targetPm2:i,busy:o,online:p,label:a("开始","Start"),className:"rounded-lg bg-emerald-500/20 text-emerald-100 ring-emerald-500/30",baseLock:!1,onRun:()=>void tz("start",i),notify:w,t:a,compact:!0}),(0,n.jsx)(eQ,{kind:"stop",targetPm2:i,busy:o,online:p,label:a("停止","Stop"),className:"rounded-lg bg-rose-500/15 text-rose-100 ring-rose-500/25",baseLock:!1,onRun:()=>void tz("stop",i),notify:w,t:a,compact:!0}),(0,n.jsx)(eQ,{kind:"restart",targetPm2:i,busy:o,online:p,label:a("重新开始","Restart"),className:"rounded-lg bg-amber-500/15 text-amber-100 ring-amber-500/25",baseLock:!1,onRun:()=>void tz("restart",i),notify:w,t:a,compact:!0}),g?(0,n.jsxs)("button",{type:"button",onClick:()=>{window.open((0,ex.p)(g.url),"_blank","noopener,noreferrer")},className:"inline-flex min-h-[2rem] items-center justify-center rounded-lg border border-emerald-500/25 bg-emerald-500/10 px-2.5 py-1.5 text-emerald-100 ring-1 ring-emerald-500/20 transition hover:bg-emerald-500/20",title:"".concat(a("打开该线路 Neko 工作室","Open this lane's Neko studio")," \xb7 ").concat(g.label).concat(g.port?" :".concat(g.port):""),"aria-label":"".concat(a("打开该线路 Neko 工作室","Open this lane's Neko studio")," \xb7 ").concat(g.label),children:[(0,n.jsx)("span",{className:"sr-only",children:a("打开该线路 Neko 工作室","Open this lane's Neko studio")}),(0,n.jsx)("span",{"aria-hidden":!0,className:"text-sm leading-none",children:"\uD83D\uDC31"}),(0,n.jsx)(Z.Z,{className:"ml-1 h-3.5 w-3.5 shrink-0","aria-hidden":!0})]}):null]})]},e.id)})})]})})]}),"single"===R?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("YouTube 相关设置","YouTube settings")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:a("串流参数写进 youtube.ini,无需 Google 登录。","Stream settings go to youtube.ini — no Google login.")}),(0,n.jsxs)("div",{className:"mt-4 space-y-3",children:[(0,n.jsx)("label",{className:"block text-xs text-zinc-400",children:a("串流密钥","Stream key")}),(0,n.jsx)("input",{className:"w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm font-mono text-zinc-200",spellCheck:!1,autoComplete:"off",value:D.key,onChange:e=>A(t=>({...t,key:e.target.value})),placeholder:"xxxx-xxxx-xxxx-xxxx-xxxx"}),(0,n.jsxs)("div",{className:"grid gap-3 sm:grid-cols-3",children:[(0,n.jsxs)("label",{className:"flex flex-col gap-1 text-xs text-zinc-400",children:["RTMPS",(0,n.jsxs)("select",{className:"rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-sm text-white",value:D.rtmps?"1":"0",onChange:e=>A(t=>({...t,rtmps:"1"===e.target.value})),children:[(0,n.jsx)("option",{value:"1",children:a("是(默认)","Yes")}),(0,n.jsx)("option",{value:"0",children:a("否 → RTMP","No")})]})]}),(0,n.jsxs)("label",{className:"flex flex-col gap-1 text-xs text-zinc-400",children:[a("比特率 kbps","Bitrate kbps"),(0,n.jsx)("input",{className:"rounded-lg border border-white/10 bg-black/40 px-3 py-2 font-mono text-sm",value:D.bitrate,onChange:e=>A(t=>({...t,bitrate:e.target.value})),placeholder:"4000"})]}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2 pt-6 text-xs text-zinc-300",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:D.fastAudio,onChange:e=>A(t=>({...t,fastAudio:e.target.checked}))}),"fast_audio(",a("轻量音频","lighter audio"),")"]})]})]}),(0,n.jsxs)("div",{className:"mt-4 flex flex-wrap gap-2",children:[(0,n.jsxs)("button",{type:"button",disabled:tS,onClick:()=>void ti(),className:"inline-flex items-center gap-2 rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-200",children:[(0,n.jsx)(y.Z,{className:"h-3.5 w-3.5 ".concat(K?"animate-spin":"")}),a("重新读取","Reload")]}),(0,n.jsxs)("button",{type:"button",disabled:tS,onClick:()=>void tc(),className:"inline-flex items-center gap-2 rounded-xl bg-violet-500/25 px-4 py-2 text-sm font-medium text-violet-100 ring-1 ring-violet-500/35",children:[K?(0,n.jsx)(v.Z,{className:"h-4 w-4 animate-spin"}):null,a("保存 youtube.ini","Save youtube.ini")]}),(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void td(),className:"rounded-xl border border-cyan-500/20 bg-cyan-500/10 px-4 py-2 text-sm text-cyan-100",children:a("平衡预设","Balanced preset")}),(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>{A(ep(E)),H(a("已从下方原文同步到表单","Synced from raw"))},className:"rounded-xl border border-white/10 px-4 py-2 text-sm text-zinc-400",children:a("从原文同步表单","Parse raw")})]}),(0,n.jsxs)("details",{className:"mt-4 rounded-xl border border-white/5 bg-black/20 p-3",children:[(0,n.jsx)("summary",{className:"cursor-pointer text-xs text-zinc-500",children:a("高级:youtube.ini 原文","Raw youtube.ini")}),(0,n.jsx)("textarea",{className:"mt-2 h-36 w-full resize-y rounded-lg border border-white/10 bg-black/50 p-3 font-mono text-[11px] text-zinc-400",value:E,onChange:e=>I(e.target.value),spellCheck:!1}),(0,n.jsx)("button",{type:"button",disabled:tS,className:"mt-2 rounded-lg bg-cyan-500/15 px-3 py-1.5 text-xs text-cyan-200",onClick:()=>void to(E),children:a("保存原文","Save raw")})]}),O?(0,n.jsx)("p",{className:"mt-2 font-mono text-xs text-zinc-500",children:O}):null]}):(0,n.jsxs)("div",{className:"space-y-6",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsxs)("h3",{className:"text-sm font-semibold text-white",children:[a("当前线路","Current lane"),e4?(0,n.jsxs)("span",{className:"ml-2 font-normal text-zinc-400",children:["\xb7 ",e4.name]}):null,ts?(0,n.jsx)("span",{className:"ml-2 rounded-md bg-amber-500/15 px-2 py-0.5 text-[10px] font-medium text-amber-100 ring-1 ring-amber-500/25",children:a("有未保存修改","Unsaved")}):null]}),e4?(0,n.jsxs)("p",{className:"mt-0.5 font-mono text-[11px] text-zinc-500",children:["PM2: ",e9,te?" → ".concat(e7):""," \xb7 ","key ",tx||"—"]}):null]}),(0,n.jsxs)("button",{type:"button",disabled:tS,className:"inline-flex items-center gap-1 rounded-lg bg-violet-500/20 px-3 py-1.5 text-xs text-violet-100 ring-1 ring-violet-500/30",onClick:()=>{let e=eZ(),t={id:e,name:"".concat(a("线路","Ch")," ").concat(L.length+1),streamKey:"",urlLines:"",pm2Name:eO(e),notes:""};es(s=>({...s,[e]:eG(t)})),e3([...L,t]),U(e),ew.current=eM(t),u(ew.current),ez("")},children:[(0,n.jsx)(e_.Z,{className:"h-3.5 w-3.5"}),a("新增线路","Add lane")]})]}),e4?(0,n.jsxs)("div",{className:"mt-4 space-y-3 border-t border-white/5 pt-4",children:[(0,n.jsx)("input",{className:"w-full rounded-xl border border-white/10 bg-black/40 px-3 py-2 text-sm",value:null!==(s=null==e6?void 0:e6.name)&&void 0!==s?s:"",onChange:e=>e8("name",e.target.value),placeholder:a("线路名称","Lane name")}),(0,n.jsx)("label",{className:"block text-xs text-zinc-500",children:a("串流密钥","Stream key")}),(0,n.jsx)("input",{className:"w-full rounded-xl border border-white/10 bg-black/40 px-3 py-2 font-mono text-sm",spellCheck:!1,value:null!==(l=null==e6?void 0:e6.streamKey)&&void 0!==l?l:"",onChange:e=>e8("streamKey",e.target.value),placeholder:"xxxx-xxxx… / rtmp(s)://…"}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void ta(),className:"rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-100",children:en?a("保存中...","Saving..."):a("保存线路设置","Save lane")}),(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void tp(),className:"rounded-xl bg-violet-500/25 px-4 py-2 text-sm font-medium text-violet-100 ring-1 ring-violet-500/35",children:a("写入 youtube.ini","Write youtube.ini")})]}),tt.ok?null:(0,n.jsx)("p",{className:"text-xs text-rose-300",children:tt.message}),(0,n.jsxs)("details",{className:"rounded-xl border border-white/5 bg-black/20 p-3",children:[(0,n.jsx)("summary",{className:"cursor-pointer text-xs text-zinc-500",children:a("高级:进程名","Advanced: process name")}),(0,n.jsx)("input",{className:"mt-2 w-full rounded-lg border border-white/10 bg-black/40 px-3 py-2 font-mono text-xs",value:null!==(i=null==e6?void 0:e6.pm2Name)&&void 0!==i?i:eO(e4.id),onChange:e=>e8("pm2Name",e.target.value),spellCheck:!1,placeholder:"youtube2__…"}),(0,n.jsxs)("p",{className:"mt-2 font-mono text-[11px] text-zinc-500",children:[a("实际生效","Effective"),": ",e7||"—"]}),tt.message&&!tt.ok?(0,n.jsx)("p",{className:"mt-2 text-[11px] text-rose-300",children:tt.message}):null]}),(0,n.jsx)("textarea",{className:"h-16 w-full resize-y rounded-xl border border-white/10 bg-black/40 p-3 text-xs text-zinc-300",value:null!==(r=null==e6?void 0:e6.notes)&&void 0!==r?r:"",onChange:e=>e8("notes",e.target.value),placeholder:a("备注(可选)","Notes (optional)")}),ei?(0,n.jsx)("p",{className:"text-xs text-zinc-400",children:ei}):null,(0,n.jsxs)("button",{type:"button",disabled:tS||L.length<2,className:"inline-flex items-center gap-1 text-xs text-rose-300 hover:text-rose-200 disabled:opacity-30",onClick:()=>{var e;let t=L.filter(e=>e.id!==e4.id);es(e=>{let t={...e};return delete t[e4.id],t}),e3(t),U((null===(e=t[0])||void 0===e?void 0:e.id)||"")},children:[(0,n.jsx)(ed.Z,{className:"h-3.5 w-3.5"}),a("删除此线路","Delete lane")]})]}):null]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("直播地址列表","URL list")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:a("每条线路独立写入自己的 URL_config..ini,不再复用或回填所谓“全局地址”。","Each lane writes to its own URL_config..ini with no shared global URL draft.")}),(0,n.jsx)("p",{className:"mt-1 font-mono text-[10px] text-zinc-600",children:x?eb(x):"URL_config.ini"}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2 text-[11px]",children:[(0,n.jsxs)("span",{className:"rounded-full border border-cyan-500/20 bg-cyan-500/10 px-2.5 py-1 text-cyan-100",children:[a("有效地址","Valid URLs"),": ",tg]}),(0,n.jsxs)("span",{className:"rounded-full border border-violet-500/20 bg-violet-500/10 px-2.5 py-1 text-violet-100",children:["Douyin: ",tf]})]}),tC,Q?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:Q}):null,(0,n.jsx)("textarea",{className:"mt-4 min-h-[160px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300",value:W,onChange:e=>{ec.current=!0,ez(e.target.value)},spellCheck:!1,placeholder:"https://live.douyin.com/..."}),(0,n.jsx)("div",{className:"mt-3 flex flex-wrap gap-2",children:(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void tu(),className:"rounded-xl bg-cyan-500/20 px-4 py-2 text-sm text-cyan-100 ring-1 ring-cyan-500/30",children:a("保存地址","Save URLs")})})]})]}),"single"===R?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("直播地址列表 \xb7 URL_config.ini","URL_config.ini")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:a("一行一个地址;可自动刷新或手动重新读取。","One URL per line; auto-refresh or reload.")}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2 text-[11px]",children:[(0,n.jsxs)("span",{className:"rounded-full border border-cyan-500/20 bg-cyan-500/10 px-2.5 py-1 text-cyan-100",children:[a("有效地址","Valid URLs"),": ",tg]}),(0,n.jsxs)("span",{className:"rounded-full border border-violet-500/20 bg-violet-500/10 px-2.5 py-1 text-violet-100",children:["Douyin: ",tf]})]}),tC,Q?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:Q}):null,(0,n.jsx)("textarea",{className:"mt-4 min-h-[200px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300",value:m,onChange:e=>{ec.current=!0,ek(e.target.value)},spellCheck:!1}),(0,n.jsx)("button",{type:"button",disabled:tS,onClick:()=>void tm(),className:"mt-3 rounded-xl bg-cyan-500/20 px-4 py-2 text-sm text-cyan-100 ring-1 ring-cyan-500/30",children:a("保存 URL 配置","Save URL config")})]}):null,(0,n.jsx)(ev,{t:a,currentProc:x,fetchJson:g,urlListText:"single"===R?m:W,keySuffixUi:tx,showKeyRow:!0,pollMs:800,refreshToken:ea})]})}var e1=s(257);let e5=()=>void 0!==e1&&e1.env.NEXT_PUBLIC_API_URL||"";function e2(e){if(null==e||!Number.isFinite(e))return"—";if(0===e)return"0 B";let t=["B","KB","MB","GB","TB"],s=e,n=0;for(;s>=1024&&n=10||0===n?0:1)," ").concat(t[n])}function e3(e){let t=e2(e);return"—"===t?t:"".concat(t,"/s")}function e4(e){return"online"===e||"running"===e?"bg-emerald-500/15 text-emerald-300 ring-1 ring-emerald-500/30":"configured"===e?"bg-sky-500/15 text-sky-200 ring-1 ring-sky-500/25":"skipped"===e?"bg-slate-500/15 text-slate-300 ring-1 ring-slate-500/30":"stopped"===e||"not_found"===e?"bg-zinc-500/15 text-zinc-400 ring-1 ring-zinc-500/25":"error"===e?"bg-rose-500/15 text-rose-300 ring-1 ring-rose-500/35":"bg-violet-500/15 text-violet-200 ring-1 ring-violet-500/30"}function e6(e,t){let s=(e||"").trim().toLowerCase();return"online"===s||"running"===s?t("运行中","Running"):"configured"===s?t("已配置","Configured"):"not_found"===s?t("未注册","Unregistered"):"stopped"===s?t("已停止","Stopped"):"error"===s?t("异常","Error"):e||"—"}function e8(){var e,t,s,L,M,T,U,E,I,D,A,Z,O,H,B,K,F,W,J,G,V,q,X,$,Q,ee,et,es,en,el,ei,ea,eo,ec,ed,eu,em,eh,ep,eb,eg,ef,ev,ey,ew,eN,ej,ek,eS,e_,eR,eP,eL,eM,eT,eU,eE,eI,eD;let eA=e5(),[eZ,eO]=(0,_.useState)("zh"),[eH,eB]=(0,_.useState)("dark"),[eK,eF]=(0,_.useState)("dashboard"),[eW,eY]=(0,_.useState)(!1),[eJ,eG]=(0,_.useState)(null),[eV,eq]=(0,_.useState)(null),[eX,e$]=(0,_.useState)(!0),[eQ,e1]=(0,_.useState)(null),[e8,e9]=(0,_.useState)(null),[e7,te]=(0,_.useState)(null),[tt,ts]=(0,_.useState)(!0),[tn,tl]=(0,_.useState)([]),[ti,tr]=(0,_.useState)([]),[ta,to]=(0,_.useState)(""),[tc,td]=(0,_.useState)(""),[tx,tu]=(0,_.useState)("/sdcard/app.apk"),[tm,th]=(0,_.useState)(""),[tp,tb]=(0,_.useState)(null),[tg,tf]=(0,_.useState)(null),[tv,ty]=(0,_.useState)(!0),[tw,tN]=(0,_.useState)(!0),tj=(0,_.useRef)(null),tk=(0,_.useRef)(null),tz=(0,_.useRef)(ta),tS=(0,_.useRef)(0),t_=(0,_.useRef)(null),tC=(0,_.useCallback)((e,t)=>"zh"===eZ?e:t,[eZ]),tR=(0,_.useCallback)(e=>{e9(e),null!=t_.current&&window.clearTimeout(t_.current),t_.current=window.setTimeout(()=>{e9(null),t_.current=null},2800)},[]),tP=(0,_.useCallback)(async(e,t)=>(0,Y.N)("".concat(eA).concat(e),t),[eA]),tL=(0,_.useCallback)(async()=>{if(tj.current)return tj.current;let e=(async()=>{try{var e;let[t,s]=await Promise.allSettled([tP("/hub/dashboard"),tP("/deploy/check")]);if("fulfilled"!==t.status)throw t.reason;let n=t.value;eG(n),eq(null),te(Date.now()),"fulfilled"===s.status?tf(s.value):tf(null);let l=(null===(e=n.android)||void 0===e?void 0:e.devices)||[];if(l.length&&!tm){let e=l.find(e=>"device"===(e.state||"").toLowerCase());th((null!=e?e:l[0]).serial)}}catch(e){eq(e.message),tf(null)}finally{e$(!1),tj.current=null}})();return tj.current=e,e},[tm,tP]),tM=(0,_.useMemo)(()=>{let e=new URLSearchParams({light:"1"});return"live_youtube"===eK?e.set("family","youtube"):"live_tiktok"===eK&&e.set("family","tiktok"),"/process_monitor?".concat(e.toString())},[eK]),tT=(0,_.useCallback)(async()=>{if(tk.current)return tk.current;let e=(async()=>{try{let e=(await tP(tM)).entries||[];tr(e),tl(e.map(e=>({pm2:e.pm2,script:e.script,label:e.label}))),te(Date.now()),to(t=>!e.length||t&&e.some(e=>e.pm2===t)?t:e[0].pm2)}catch(e){}finally{tk.current=null}})();return tk.current=e,e},[tP,tM]);(0,_.useEffect)(()=>{let e=window.localStorage.getItem("live-hub-lang");("zh"===e||"en"===e)&&eO(e);let t=window.localStorage.getItem("live-hub-theme");("light"===t||"dark"===t)&&eB(t)},[]),(0,_.useEffect)(()=>{window.localStorage.setItem("live-hub-lang",eZ)},[eZ]),(0,_.useEffect)(()=>{document.documentElement.setAttribute("data-theme",eH);try{window.localStorage.setItem("live-hub-theme",eH)}catch(e){}},[eH]),(0,_.useEffect)(()=>{let e=()=>ts("visible"===document.visibilityState);return e(),document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[]),(0,_.useEffect)(()=>{if(!eW)return;let e=e=>{"Escape"===e.key&&eY(!1)};window.addEventListener("keydown",e);let t=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{window.removeEventListener("keydown",e),document.body.style.overflow=t}},[eW]),(0,_.useEffect)(()=>()=>{null!=t_.current&&window.clearTimeout(t_.current)},[]),(0,_.useEffect)(()=>{try{"0"===localStorage.getItem("livehub.autorefresh")&&ty(!1),"0"===localStorage.getItem("livehub.showStreamProbes")&&tN(!1)}catch(e){}},[]),(0,_.useEffect)(()=>{tL()},[tL]),(0,_.useEffect)(()=>{tT()},[tT]),(0,_.useEffect)(()=>{if(!tv||!tt||"live_youtube"===eK||"live_tiktok"===eK)return;let e=window.setInterval(()=>{tL()},1e4);return()=>clearInterval(e)},[tv,tt,tL,eK]),(0,_.useEffect)(()=>{if(!tv||!tt)return;let e=window.setInterval(()=>{tT()},"live_youtube"===eK||"live_tiktok"===eK?700:4e3);return()=>clearInterval(e)},[tv,tt,tT,eK]),(0,_.useEffect)(()=>{tz.current=ta},[ta]),(0,_.useEffect)(()=>{ta&&"live_youtube"===eK&&(async()=>{let e=tz.current.trim(),t=++tS.current;try{let s=new URLSearchParams({process:e,_ts:String(Date.now())}),n=await tP("/get_url_config?".concat(s));if(t!==tS.current||e!==tz.current.trim())return;td(n.content||"")}catch(e){}})()},[ta,tP,eK]),(0,_.useEffect)(()=>{"settings"===eK&&(async()=>{try{let e=await tP("/hub/config");tb(e)}catch(e){tb(null)}})()},[tP,eK]);let tU=(0,_.useMemo)(()=>{var e;let t=(null==eJ?void 0:null===(e=eJ.stack)||void 0===e?void 0:e.quick_links)||{},s={};for(let[e,n]of Object.entries(t))/^https?:\/\//i.test(n)?s[e]=(0,ex.p)(n):s[e]=n;return s},[null==eJ?void 0:null===(e=eJ.stack)||void 0===e?void 0:e.quick_links]),tE=(0,_.useMemo)(()=>(0,eC.O0)(tU),[tU]),tI=(0,_.useMemo)(()=>(0,eC.Tc)(tE),[tE]),tD=async(e,t)=>{e1("svc:".concat(e));try{let s=await tP("/service_action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({service:e,action:t})});"error"===s.status?tR(s.detail||s.message||tC("操作失败","Action failed")):tR(s.message||"OK"),await tL()}catch(e){tR(e.message)}finally{e1(null)}},tA=async(e,t)=>{let s=(null!=t?t:ta).trim();if(s){e1("proc:".concat(e,":").concat(s));try{let t=await tP("/".concat(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({process:s})});tR(String(t.output||t.message||"OK")),await tT(),"live_youtube"===eK||"live_tiktok"===eK?tL():await tL()}catch(e){tR(e.message)}finally{e1(null)}}},tZ=async(e,t)=>{let s=(null!=t?t:ta).trim();if(!s)return;let n=null!=e?e:tc,l=++tS.current;e1("save:url");try{let e=new URLSearchParams({process:s});await tP("/save_url_config?".concat(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:n})}),l===tS.current&&s===tz.current.trim()&&td(n),tR(tC("URL 配置已保存","URL config saved"))}catch(e){throw tR(e.message),e}finally{e1(null)}},tO=async function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!tm){tR(tC("请选择设备","Pick a device"));return}e1("adb:".concat(e));try{let s=await tP("/android/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,serial:tm,payload:t})});tR(s.message||"OK")}catch(e){tR(e.message)}finally{e1(null)}},tH=[{id:"dashboard",icon:r.Z,labelZh:"总览",labelEn:"Dashboard"},{id:"services",icon:a.Z,labelZh:"服务",labelEn:"Services"},{id:"live_youtube",icon:o.Z,labelZh:"YouTube 无人直播",labelEn:"YouTube unmanned"},{id:"live_tiktok",icon:c.Z,labelZh:"TikTok 无人直播",labelEn:"TikTok unmanned"},{id:"android",icon:d.Z,labelZh:"安卓",labelEn:"Android"},{id:"network",icon:x.Z,labelZh:"网络",labelEn:"Network"},{id:"settings",icon:u.Z,labelZh:"设置",labelEn:"Settings"}],tB=e=>{(async()=>{var t;if(null===(t=navigator.clipboard)||void 0===t?void 0:t.writeText){await navigator.clipboard.writeText(e);return}let s=document.createElement("textarea");s.value=e,s.readOnly=!0,s.style.position="fixed",s.style.opacity="0",document.body.appendChild(s),s.select(),document.execCommand("copy"),s.remove()})().then(()=>tR(tC("已复制","Copied")),()=>tR(tC("复制失败","Copy failed")))},tK=null!==(ev=null==eJ?void 0:null===(t=eJ.services)||void 0===t?void 0:t.filter(e=>e.running&&e.available).length)&&void 0!==ev?ev:0,tF=null!==(ey=null==eJ?void 0:null===(s=eJ.services)||void 0===s?void 0:s.length)&&void 0!==ey?ey:0,tW=e7?new Date(e7).toLocaleTimeString("zh"===eZ?"zh-CN":"en-US",{hour12:!1}):tC("未同步","Not synced"),tY=tt?tC("前台自动刷新","Auto refresh"):tC("后台已暂停刷新","Refresh paused in background");return(0,n.jsxs)("div",{className:"lp-root min-h-screen transition-colors duration-300 ".concat("light"===eH?"bg-slate-100 text-slate-900 selection:bg-violet-400/25":"bg-[#050508] text-zinc-100 selection:bg-violet-500/30"),children:[(0,n.jsx)("div",{className:"lp-noise pointer-events-none fixed inset-0 z-0 ".concat("light"===eH?"opacity-[0.06]":"opacity-[0.22]"),"aria-hidden":!0}),(0,n.jsx)("div",{className:"lp-aurora pointer-events-none fixed -left-1/4 top-0 h-[42rem] w-[42rem] rounded-full blur-[120px] ".concat("light"===eH?"bg-violet-400/15":"bg-violet-600/20"),"aria-hidden":!0}),(0,n.jsx)("div",{className:"lp-aurora2 pointer-events-none fixed bottom-0 right-0 h-[36rem] w-[36rem] rounded-full blur-[100px] ".concat("light"===eH?"bg-cyan-400/10":"bg-cyan-500/10"),"aria-hidden":!0}),e8?(0,n.jsx)(l.E.div,{initial:{opacity:0,y:16},animate:{opacity:1,y:0},role:"status","aria-live":"polite","aria-atomic":"true",className:"fixed bottom-6 left-1/2 z-[100] max-w-md -translate-x-1/2 rounded-2xl border border-white/10 bg-zinc-950/95 px-5 py-3 text-center text-sm text-zinc-100 shadow-2xl shadow-black/50 backdrop-blur-xl",children:e8}):null,(0,n.jsxs)("div",{className:"relative z-10 flex min-h-screen",children:[(0,n.jsxs)("aside",{className:"hidden w-64 shrink-0 flex-col border-r px-4 py-6 backdrop-blur-2xl lg:flex ".concat("light"===eH?"border-slate-200/90 bg-white/70":"border-white/[0.06] bg-zinc-950/40"),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 px-2",children:[(0,n.jsx)("div",{className:"flex h-9 w-9 items-center justify-center rounded-xl bg-gradient-to-br from-violet-500 to-cyan-400 shadow-lg shadow-violet-500/25",children:(0,n.jsx)(m.Z,{className:"h-4 w-4 text-white"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-[0.2em] ".concat("light"===eH?"text-slate-500":"text-zinc-500"),children:"live.local"}),(0,n.jsx)("p",{className:"text-sm font-semibold ".concat("light"===eH?"text-slate-900":"text-white"),children:tC("无人直播系统","Unmanned Live System")})]})]}),(0,n.jsx)("nav",{className:"mt-10 flex flex-1 flex-col gap-1",children:tH.map(e=>{let t=e.icon,s=eK===e.id;return(0,n.jsxs)("button",{type:"button",onClick:()=>eF(e.id),"aria-current":s?"page":void 0,className:"flex items-center gap-3 rounded-xl px-3 py-2.5 text-left text-sm font-medium transition ".concat("light"===eH?s?"bg-violet-100/90 text-slate-900 shadow-inner shadow-violet-200/50":"text-slate-600 hover:bg-slate-200/60 hover:text-slate-900":s?"bg-white/[0.08] text-white shadow-inner shadow-white/5":"text-zinc-500 hover:bg-white/[0.04] hover:text-zinc-200"),children:[(0,n.jsx)(t,{className:"h-4 w-4 ".concat("light"===eH?s?"text-violet-600":"text-slate-400":s?"text-violet-300":"text-zinc-600")}),tC(e.labelZh,e.labelEn),s?(0,n.jsx)(h.Z,{className:"ml-auto h-4 w-4 ".concat("light"===eH?"text-slate-400":"text-zinc-600")}):null]},e.id)})})]}),(0,n.jsxs)("div",{className:"flex min-w-0 flex-1 flex-col",children:[(0,n.jsxs)("header",{className:"sticky top-0 z-20 flex items-center justify-between gap-3 border-b px-4 py-3 backdrop-blur-xl lg:px-8 ".concat("light"===eH?"border-slate-200/80 bg-white/75 text-slate-900":"border-white/[0.06] bg-zinc-950/70 text-white"),children:[(0,n.jsxs)("div",{className:"flex min-w-0 items-center gap-3",children:[(0,n.jsx)("button",{type:"button",className:"rounded-xl border p-2 lg:hidden ".concat("light"===eH?"border-slate-200 bg-white/80":"border-white/10 bg-white/5"),onClick:()=>eY(!0),"aria-label":"Menu",children:(0,n.jsx)(p.Z,{className:"h-5 w-5"})}),(0,n.jsxs)("div",{className:"min-w-0",children:[(0,n.jsx)("h1",{className:"truncate text-lg font-semibold tracking-tight lg:text-xl ".concat("light"===eH?"text-slate-900":"text-white"),children:tC((null===(L=tH.find(e=>e.id===eK))||void 0===L?void 0:L.labelZh)||"",(null===(M=tH.find(e=>e.id===eK))||void 0===M?void 0:M.labelEn)||"")}),(0,n.jsxs)("p",{className:"truncate text-xs ".concat("light"===eH?"text-slate-500":"text-zinc-500"),children:[(null==eJ?void 0:null===(T=eJ.stack)||void 0===T?void 0:T.mdns_host)||"live.local"," \xb7"," ","dark"===eH?tC("夜间","Dark mode"):tC("日间","Light mode")," \xb7 ",tY," \xb7"," ",tC("最后同步","Last sync")," ",tW]})]})]}),(0,n.jsxs)("div",{className:"flex shrink-0 items-center gap-1.5 sm:gap-2",children:[(0,n.jsx)("button",{type:"button",onClick:()=>eB(e=>"dark"===e?"light":"dark"),className:"rounded-xl border p-2 transition ".concat("light"===eH?"border-slate-200 bg-white text-amber-500 shadow-sm":"border-white/10 bg-white/[0.06] text-violet-200"),title:"dark"===eH?tC("切换到日间","Switch to light"):tC("切换到夜间","Switch to dark"),"aria-label":"dark"===eH?tC("日间模式","Light mode"):tC("夜间模式","Dark mode"),"aria-pressed":"light"===eH,children:"dark"===eH?(0,n.jsx)(b.Z,{className:"h-5 w-5",strokeWidth:2}):(0,n.jsx)(g.Z,{className:"h-5 w-5",strokeWidth:2})}),(0,n.jsxs)("button",{type:"button",onClick:()=>eO(e=>"zh"===e?"en":"zh"),className:"relative rounded-xl border p-2 transition ".concat("light"===eH?"border-slate-200 bg-white text-cyan-600 shadow-sm":"border-white/10 bg-white/[0.06] text-cyan-200"),title:"zh"===eZ?"English":"中文","aria-label":tC("切换语言","Toggle language"),"aria-pressed":"en"===eZ,children:[(0,n.jsx)(f.Z,{className:"h-5 w-5",strokeWidth:2}),(0,n.jsx)("span",{className:"absolute -bottom-0.5 -right-0.5 flex h-4 min-w-[1rem] items-center justify-center rounded px-0.5 text-[9px] font-bold leading-none ".concat("light"===eH?"bg-cyan-100 text-cyan-800":"bg-cyan-500/30 text-cyan-100"),children:"zh"===eZ?"中":"A"})]}),(0,n.jsxs)("button",{type:"button",disabled:!!eQ,onClick:()=>void Promise.all([tL(),tT()]),className:"flex items-center gap-2 rounded-xl border px-3 py-2 text-xs font-medium transition disabled:opacity-40 ".concat("light"===eH?"border-slate-200 bg-white text-slate-700 hover:bg-slate-50":"border-white/10 bg-white/[0.04] text-zinc-300 hover:bg-white/[0.07]"),children:[eQ?(0,n.jsx)(v.Z,{className:"h-3.5 w-3.5 animate-spin"}):(0,n.jsx)(y.Z,{className:"h-3.5 w-3.5"}),(0,n.jsx)("span",{className:"hidden sm:inline",children:tC("刷新","Refresh")})]})]})]}),(0,n.jsx)("main",{className:"flex-1 px-4 py-6 lg:px-8 lg:py-8",children:(0,n.jsx)(i.M,{mode:"wait",children:(0,n.jsxs)(l.E.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},exit:{opacity:0,y:-6},transition:{duration:.28,ease:[.22,1,.36,1]},children:["dashboard"===eK?(0,n.jsxs)("div",{className:"space-y-6",children:[eV?(0,n.jsxs)("div",{className:"rounded-2xl border border-rose-500/25 bg-rose-950/20 p-4 text-sm text-rose-200",children:[tC("无法加载仪表盘:","Dashboard error: "),eV]}):null,(0,n.jsx)(l.E.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:.02},className:"rounded-2xl border p-2 backdrop-blur-xl ".concat("light"===eH?"border-slate-200/90 bg-white/80 shadow-sm shadow-slate-200/30":"border-white/[0.07] bg-zinc-950/30"),children:(0,n.jsx)(R.Z,{snapshot:null!==(ew=null==eJ?void 0:eJ.snapshot)&&void 0!==ew?ew:null,theme:eH,tr:tC})}),(0,n.jsx)(l.E.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:.05},className:"rounded-2xl border p-3 shadow-lg ".concat("light"===eH?"border-fuchsia-200/80 bg-gradient-to-br from-fuchsia-50/90 via-white to-cyan-50/70 shadow-fuchsia-100/40":"border-fuchsia-500/20 bg-gradient-to-br from-fuchsia-500/10 via-zinc-950/60 to-cyan-500/10 shadow-fuchsia-900/10"),children:(0,n.jsx)(C,{tr:tC})}),(0,n.jsx)("div",{className:"grid gap-2 sm:grid-cols-2 xl:grid-cols-5",children:[{icon:w.Z,label:tC("CPU 1m","CPU 1m"),value:null!==(eN=null==eJ?void 0:null===(I=eJ.snapshot)||void 0===I?void 0:null===(E=I.cpu_load)||void 0===E?void 0:null===(U=E["1m"])||void 0===U?void 0:U.toFixed(2))&&void 0!==eN?eN:"—",sub:tC("负载均值","Load avg")},{icon:r.Z,label:tC("内存","Memory"),value:e2(null==eJ?void 0:null===(A=eJ.snapshot)||void 0===A?void 0:null===(D=A.memory)||void 0===D?void 0:D.available),sub:"/ ".concat(e2(null==eJ?void 0:null===(O=eJ.snapshot)||void 0===O?void 0:null===(Z=O.memory)||void 0===Z?void 0:Z.total))},{icon:N.Z,label:tC("磁盘可用","Disk free"),value:e2(null==eJ?void 0:null===(B=eJ.snapshot)||void 0===B?void 0:null===(H=B.disk)||void 0===H?void 0:H.free),sub:"/ ".concat(e2(null==eJ?void 0:null===(F=eJ.snapshot)||void 0===F?void 0:null===(K=F.disk)||void 0===K?void 0:K.total))},{icon:a.Z,label:tC("服务在线","Services up"),value:"".concat(tK,"/").concat(tF||"—"),sub:tC("基础服务层","Infra layer")},{icon:j.Z,label:tC("运行时间","Uptime"),value:function(e){if(null==e||!Number.isFinite(e))return"—";let t=Math.max(0,Math.floor(e)),s=Math.floor(t/86400),n=Math.floor(t%86400/3600),l=Math.floor(t%3600/60);return s>0?"".concat(s,"d ").concat(n,"h"):n>0?"".concat(n,"h ").concat(l,"m"):"".concat(l,"m")}(null==eJ?void 0:null===(W=eJ.snapshot)||void 0===W?void 0:W.uptime_seconds),sub:tC("自开机","Since boot")}].map((e,t)=>(0,n.jsxs)(l.E.div,{initial:{opacity:0,y:12},animate:{opacity:1,y:0},transition:{delay:.05*t,duration:.35,ease:[.22,1,.36,1]},whileHover:{y:-2},className:"group relative overflow-hidden rounded-xl border border-white/[0.07] bg-gradient-to-br from-white/[0.05] to-transparent p-3 shadow-lg shadow-black/20",children:[(0,n.jsx)("div",{className:"absolute -right-4 -top-4 h-16 w-16 rounded-full bg-violet-500/10 blur-xl transition group-hover:bg-violet-500/18"}),(0,n.jsx)(e.icon,{className:"h-4 w-4 text-violet-300/90"}),(0,n.jsx)("p",{className:"mt-2 text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:e.label}),(0,n.jsx)("p",{className:"mt-0.5 font-mono text-lg font-semibold leading-tight text-white",children:eX?"…":e.value}),(0,n.jsx)("p",{className:"mt-0.5 text-[10px] text-zinc-500",children:e.sub})]},e.label))}),(null==eJ?void 0:eJ.hardware)&&"object"==typeof eJ.hardware?(0,n.jsxs)("div",{className:"rounded-2xl border border-indigo-500/25 bg-gradient-to-br from-indigo-500/[0.1] via-zinc-950/70 to-violet-500/[0.08] p-6 shadow-2xl shadow-indigo-500/5",children:[(0,n.jsx)("h3",{className:"text-base font-semibold text-white",children:tC("系统硬件与软件能力","Hardware & software profile")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("来自 hardware_probe;用于直播/解码策略参考。","From hardware_probe; guides decode/streaming posture.")}),(0,n.jsxs)("div",{className:"mt-5 grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-indigo-300/90",children:tC("平台","Platform")}),(0,n.jsxs)("dl",{className:"space-y-2 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"arch"}),(0,n.jsx)("dd",{className:"text-right text-zinc-200",children:String(null!==(ej=eJ.hardware.arch)&&void 0!==ej?ej:"—")})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"kernel"}),(0,n.jsx)("dd",{className:"text-right text-zinc-200",children:String(null!==(eS=null!==(ek=eJ.hardware.kernel)&&void 0!==ek?ek:null===(J=eJ.stack)||void 0===J?void 0:J.kernel)&&void 0!==eS?eS:"—")})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"Python"}),(0,n.jsx)("dd",{className:"text-right text-zinc-200",children:String(null!==(e_=null===(G=eJ.stack)||void 0===G?void 0:G.python)&&void 0!==e_?e_:"—")})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"mDNS"}),(0,n.jsx)("dd",{className:"text-right text-cyan-200/90",children:null!==(eR=null===(V=eJ.stack)||void 0===V?void 0:V.mdns_host)&&void 0!==eR?eR:"—"})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"IP"}),(0,n.jsx)("dd",{className:"text-right text-zinc-300",children:((null===(q=eJ.stack)||void 0===q?void 0:q.ips)||[]).join(" \xb7 ")||"—"})]})]})]}),(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-fuchsia-300/90",children:"GPU / NPU"}),(()=>{let e=eJ.hardware.gpu,t=eJ.hardware.npu;return(0,n.jsxs)("dl",{className:"space-y-2 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"GPU"}),(0,n.jsxs)("dd",{className:"mt-0.5 text-zinc-200",children:[(null==e?void 0:e.present)?tC("已检测","present"):tC("未检测","absent"),(null==e?void 0:e.driver)?" \xb7 ".concat(e.driver):""]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"render"}),(0,n.jsx)("dd",{className:"mt-0.5 break-all text-zinc-500",children:((null==e?void 0:e.render_nodes)||[]).join(", ")||"—"})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"NPU"}),(0,n.jsx)("dd",{className:"mt-0.5 break-all text-zinc-500",children:(null==t?void 0:t.present)?(t.devices||[]).join(", "):tC("—","—")})]})]})})()]}),(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-white/[0.06] bg-black/30 p-4 lg:col-span-2",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-emerald-300/90",children:"ffmpeg / 建议策略"}),(()=>{var e,t,s,l;let i=eJ.hardware.ffmpeg_hwaccels||[],r=eJ.hardware.recommendation;return(0,n.jsxs)("div",{className:"space-y-2 text-[11px] text-zinc-400",children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"hwaccels: "}),(0,n.jsx)("span",{className:"font-mono text-emerald-200/90",children:i.length?i.join(", "):"—"})]}),(0,n.jsxs)("div",{className:"grid gap-2 sm:grid-cols-2",children:[(0,n.jsxs)("p",{children:[(0,n.jsxs)("span",{className:"text-zinc-600",children:[tC("解码","Decoder"),": "]}),(0,n.jsx)("span",{className:"text-zinc-200",children:null!==(e=null==r?void 0:r.video_decoder)&&void 0!==e?e:"—"})]}),(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"HDMI: "}),(0,n.jsx)("span",{className:"text-zinc-200",children:null!==(t=null==r?void 0:r.hdmi_player)&&void 0!==t?t:"—"})]}),(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"Browser: "}),(0,n.jsx)("span",{className:"text-zinc-200",children:null!==(s=null==r?void 0:r.browser_hwaccel)&&void 0!==s?s:"—"})]}),(0,n.jsxs)("p",{children:[(0,n.jsxs)("span",{className:"text-zinc-600",children:[tC("稳定模式","Stability"),": "]}),(0,n.jsx)("span",{className:"text-amber-200/90",children:null!==(l=null==r?void 0:r.stability_mode)&&void 0!==l?l:"—"})]})]}),((null==r?void 0:r.degradation_reasons)||[]).length?(0,n.jsx)("ul",{className:"mt-2 list-inside list-disc space-y-1 text-[10px] text-amber-200/80",children:((null==r?void 0:r.degradation_reasons)||[]).map(e=>(0,n.jsx)("li",{children:e},e))}):null]})})()]})]})]}):null,tg?(0,n.jsxs)("div",{className:"rounded-2xl border p-5 ".concat(tg.ready?"border-emerald-500/25 bg-gradient-to-br from-emerald-500/[0.08] via-zinc-950/50 to-cyan-500/[0.05]":"border-amber-500/30 bg-gradient-to-br from-amber-500/[0.1] via-zinc-950/55 to-rose-500/[0.05]"),children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("安装验收","Deployment health")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("一键脚本完成后,本机 API、局域网入口、反向代理与 mDNS 的可用性检查。","Post-install checks for loopback API, LAN access, reverse proxy, and mDNS.")})]}),(0,n.jsx)("span",{className:"rounded-full px-3 py-1 text-[10px] font-semibold ".concat(tg.ready?"bg-emerald-500/20 text-emerald-100 ring-1 ring-emerald-500/30":"bg-amber-500/20 text-amber-100 ring-1 ring-amber-500/30"),children:tg.ready?tC("可交付","Ready"):tC("需处理","Needs attention")})]}),(0,n.jsxs)("div",{className:"mt-4 grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:tC("验收摘要","Acceptance summary")}),(0,n.jsxs)("p",{className:"mt-2 font-mono text-sm text-white",children:[null!==(eP=tg.pass_count)&&void 0!==eP?eP:0,"/",null!==(eL=tg.total_count)&&void 0!==eL?eL:0,(0,n.jsx)("span",{className:"ml-2 text-[11px] text-zinc-500",children:tC("已通过","checks passed")})]}),(0,n.jsxs)("p",{className:"mt-1 text-[11px] text-zinc-500",children:[tC("必需项","Required"),": ",null!==(eM=tg.required_total)&&void 0!==eM?eM:0," \xb7 mDNS"," ",tg.mdns_enabled?tC("已启用","enabled"):tC("已关闭","disabled")," \xb7 edge"," ",tg.live_edge_enabled?tC("已启用","enabled"):tC("已关闭","disabled")]}),(0,n.jsx)("div",{className:"mt-3 flex flex-wrap gap-2",children:Object.entries(tg.urls||{}).filter(e=>{let[,t]=e;return!!t}).slice(0,4).map(e=>{let[t,s]=e;return(0,n.jsx)("a",{href:(0,ex.p)(s),target:"_blank",rel:"noreferrer",className:"rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-[11px] text-zinc-200 ring-1 ring-white/10",children:t},t)})})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:(null===(X=tg.failing_checks)||void 0===X?void 0:X.length)?tC("失败项","Failing checks"):tC("当前状态","Current state")}),(null===($=tg.failing_checks)||void 0===$?void 0:$.length)?(0,n.jsx)("ul",{className:"mt-2 space-y-2 text-[11px] text-zinc-300",children:tg.failing_checks.slice(0,4).map(e=>(0,n.jsxs)("li",{className:"rounded-lg border border-amber-500/20 bg-amber-500/10 px-3 py-2",children:[(0,n.jsx)("span",{className:"font-semibold text-amber-100",children:e.label}),(0,n.jsx)("span",{className:"ml-2 text-zinc-400",children:e.detail||"—"})]},e.id))}):(0,n.jsx)("p",{className:"mt-2 text-[11px] text-emerald-200/90",children:tC("必需检查已全部通过,可直接用浏览器面板交付。","All required checks pass; browser control plane is ready.")}),(tg.hints||[]).length?(0,n.jsx)("ul",{className:"mt-3 list-inside list-disc space-y-1 text-[10px] text-zinc-400",children:(tg.hints||[]).slice(0,3).map(e=>(0,n.jsx)("li",{children:e},e))}):null]})]})]}):null,(null==eJ?void 0:null===(Q=eJ.stack)||void 0===Q?void 0:Q.neko_login)?(0,n.jsxs)("div",{className:"rounded-2xl border border-fuchsia-500/25 bg-gradient-to-r from-fuchsia-500/[0.08] to-violet-500/[0.06] p-5",children:[(0,n.jsxs)("h3",{className:"text-sm font-semibold text-white",children:["Neko ",tC("登录","sign-in")]}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:eJ.stack.neko_login.note_zh||tC(tI?"Neko Chromium ".concat(tI," 使用下列账号策略。"):"Neko Chromium 多实例使用下列账号策略。",tI?"Neko Chromium ".concat(tI," uses the policy below."):"Neko Chromium instances use the policy below.")}),(0,n.jsx)("p",{className:"mt-2 text-[11px] text-amber-200/85",children:tC("重要:两栏分开填——昵称随意,密码必须是环境变量里的口令(默认 12345678)。用错密码会像一直加载;勿把「用户名/密码」写在一行。","Use two fields: display name is free-form; password must match NEKO_* (default 12345678). Wrong password looks like infinite loading.")}),tE.length?(0,n.jsx)("div",{className:"mt-4 flex flex-wrap gap-2",children:tE.map(e=>(0,n.jsxs)("a",{href:e.url,target:"_blank",rel:"noreferrer",className:"rounded-lg border border-fuchsia-400/20 bg-black/25 px-3 py-2 text-[11px] text-fuchsia-100 ring-1 ring-fuchsia-400/20",children:[e.label,e.port?" :".concat(e.port):""]},e.key))}):null,(0,n.jsxs)("div",{className:"mt-4 grid gap-3 sm:grid-cols-2 font-mono text-sm",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/40 px-4 py-3",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase text-zinc-500",children:tC("昵称示例","Display Name Example")}),(0,n.jsx)("p",{className:"mt-1 text-fuchsia-200",children:null!==(eT=eJ.stack.neko_login.user_login)&&void 0!==eT?eT:"live"}),(0,n.jsx)("p",{className:"mt-2 text-[10px] uppercase text-zinc-500",children:tC("连接口令","Access Password")}),(0,n.jsx)("p",{className:"mt-0.5 text-fuchsia-100",children:null!==(eU=eJ.stack.neko_login.user_password)&&void 0!==eU?eU:"—"})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/40 px-4 py-3",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase text-zinc-500",children:tC("管理昵称示例","Admin Display Name Example")}),(0,n.jsx)("p",{className:"mt-1 text-violet-200",children:null!==(eE=eJ.stack.neko_login.admin_login)&&void 0!==eE?eE:"admin"}),(0,n.jsx)("p",{className:"mt-2 text-[10px] uppercase text-zinc-500",children:tC("管理口令","Admin Password")}),(0,n.jsx)("p",{className:"mt-0.5 text-violet-100",children:null!==(eI=eJ.stack.neko_login.admin_password)&&void 0!==eI?eI:"—"})]})]}),(0,n.jsx)("p",{className:"mt-3 text-[10px] text-zinc-600",children:tC("x86 默认使用 Neko 的 Chrome 镜像,ARM 默认使用 Chromium 镜像;默认保留管理员会话、开发者工具和 Tampermonkey 持久化。本栈未启用 Firefox 版 Neko。","x86 defaults to Neko’s Chrome image, ARM defaults to Chromium, and admin access, DevTools, plus persistent Tampermonkey stay enabled. This stack does not use Firefox Neko.")})]}):null,(null==eJ?void 0:null===(et=eJ.network)||void 0===et?void 0:null===(ee=et.interfaces)||void 0===ee?void 0:ee.length)?(0,n.jsxs)("div",{className:"rounded-2xl border border-cyan-500/15 bg-gradient-to-br from-cyan-500/[0.07] to-transparent p-5",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(k.Z,{className:"h-4 w-4 text-cyan-300"}),tC("网络带宽 / 流量","Network bandwidth / traffic")]}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("实时速率由总览自动刷新间隔计算;累计值来自系统网卡计数器。","Live rates are calculated from dashboard refresh deltas; totals come from kernel counters.")}),(0,n.jsxs)("div",{className:"mt-4 grid gap-3 sm:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/25 px-4 py-3 font-mono text-[11px]",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase tracking-[0.08em] text-cyan-300/70",children:tC("实时下行","Live down")}),(0,n.jsx)("p",{className:"mt-1 text-lg font-semibold text-cyan-100",children:e3(eJ.network.total_rx_bps)}),(0,n.jsxs)("p",{className:"mt-1 text-zinc-500",children:[tC("累计","Total"),": ",e2(eJ.network.total_rx_bytes)]})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/25 px-4 py-3 font-mono text-[11px]",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase tracking-[0.08em] text-cyan-300/70",children:tC("实时上行","Live up")}),(0,n.jsx)("p",{className:"mt-1 text-lg font-semibold text-cyan-100",children:e3(eJ.network.total_tx_bps)}),(0,n.jsxs)("p",{className:"mt-1 text-zinc-500",children:[tC("累计","Total"),": ",e2(eJ.network.total_tx_bytes)]})]})]}),(0,n.jsx)("div",{className:"mt-4 grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:(eJ.network.interfaces||[]).slice(0,6).map(e=>{var t,s,l,i;return(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/25 px-4 py-3 font-mono text-[11px]",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-cyan-200/90",children:e.name}),(0,n.jsxs)("p",{className:"mt-2 text-zinc-500",children:[tC("链路","Link"),": ",e.operstate||"unknown"," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",e.speed_mbps?"".concat(e.speed_mbps," Mbps"):tC("未知速率","unknown speed")]}),(0,n.jsxs)("p",{className:"mt-2 text-zinc-500",children:["↓ ",e3(e.rx_bps)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",e2(e.rx_bytes)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",null!==(l=null===(t=e.rx_packets)||void 0===t?void 0:t.toLocaleString())&&void 0!==l?l:"—"," pkt"]}),(0,n.jsxs)("p",{className:"mt-0.5 text-zinc-500",children:["↑ ",e3(e.tx_bps)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",e2(e.tx_bytes)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",null!==(i=null===(s=e.tx_packets)||void 0===s?void 0:s.toLocaleString())&&void 0!==i?i:"—"," pkt"]})]},e.name)})})]}):null,(null==eJ?void 0:null===(en=eJ.live_events)||void 0===en?void 0:null===(es=en.pm2_tail)||void 0===es?void 0:es.length)||(null==eJ?void 0:null===(ei=eJ.live_events)||void 0===ei?void 0:null===(el=ei.process_digest)||void 0===el?void 0:el.length)?(0,n.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-amber-500/15 bg-zinc-950/40 p-5",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("直播 / PM2 事件","Live / PM2 feed")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("PM2 合并日志尾部","PM2 merged log tail")}),(0,n.jsx)("pre",{className:"mt-3 max-h-48 overflow-auto whitespace-pre-wrap rounded-lg border border-white/[0.05] bg-black/40 p-3 font-mono text-[10px] leading-relaxed text-zinc-400",children:((null==eJ?void 0:null===(ea=eJ.live_events)||void 0===ea?void 0:ea.pm2_tail)||[]).join("\n")||tC("暂无 PM2 输出","No PM2 output")})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/15 bg-zinc-950/40 p-5",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("进程快照","Process digest")}),(0,n.jsx)("ul",{className:"mt-3 space-y-2",children:((null==eJ?void 0:null===(eo=eJ.live_events)||void 0===eo?void 0:eo.process_digest)||[]).map(e=>(0,n.jsxs)("li",{className:"flex items-center justify-between gap-2 rounded-lg border border-white/[0.05] bg-black/30 px-3 py-2 text-xs",children:[(0,n.jsx)("span",{className:"truncate text-zinc-300",children:e.label||e.pm2}),(0,n.jsx)("span",{className:"shrink-0 rounded-md px-2 py-0.5 text-[10px] font-medium ".concat(e4(e.status||"")),children:e6(e.status||"",tC)})]},e.pm2))})]})]}):null,(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/20 bg-gradient-to-br from-violet-500/[0.12] via-zinc-950/50 to-fuchsia-500/[0.06] p-5 shadow-lg shadow-violet-500/5",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("直播进程","Live processes")}),(0,n.jsx)("span",{className:"rounded-full bg-white/10 px-2 py-0.5 text-[10px] font-medium text-zinc-300",children:(null==eJ?void 0:null===(ec=eJ.live)||void 0===ec?void 0:ec.backend_mode)||"—"})]}),(0,n.jsxs)("ul",{className:"mt-4 space-y-2.5",children:[((null==eJ?void 0:null===(ed=eJ.live)||void 0===ed?void 0:ed.processes)||[]).slice(0,10).map(e=>(0,n.jsxs)("li",{className:"group flex items-center gap-3 rounded-xl border border-white/[0.08] bg-black/35 px-3 py-2.5 transition hover:border-violet-400/25 hover:bg-black/45",children:[(0,n.jsx)("div",{className:"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-violet-500/30 to-fuchsia-500/20 text-[10px] font-bold text-violet-100 ring-1 ring-white/10",children:"LIVE"}),(0,n.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,n.jsx)("p",{className:"truncate text-sm font-medium text-zinc-100",children:e.label||e.pm2}),(0,n.jsx)("p",{className:"truncate font-mono text-[10px] text-zinc-600",children:e.script||e.pm2})]}),(0,n.jsx)("span",{className:"shrink-0 rounded-lg px-2.5 py-1 text-[10px] font-semibold ".concat(e4(e.process_status||"")),children:e6(e.process_status||"",tC)})]},e.pm2)),(null==eJ?void 0:null===(em=eJ.live)||void 0===em?void 0:null===(eu=em.processes)||void 0===eu?void 0:eu.length)?null:(0,n.jsx)("li",{className:"rounded-xl border border-dashed border-white/10 py-8 text-center text-xs text-zinc-600",children:tC("暂无直播进程","No live processes")})]}),(0,n.jsxs)("div",{className:"mt-5 grid grid-cols-2 gap-2",children:[(0,n.jsx)("button",{type:"button",onClick:()=>eF("live_youtube"),className:"rounded-xl border border-violet-400/35 bg-violet-500/15 py-2.5 text-[11px] font-semibold text-violet-100 shadow-inner shadow-black/20 transition hover:bg-violet-500/25",children:"YouTube"}),(0,n.jsx)("button",{type:"button",onClick:()=>eF("live_tiktok"),className:"rounded-xl border border-cyan-400/35 bg-cyan-500/15 py-2.5 text-[11px] font-semibold text-cyan-100 shadow-inner shadow-black/20 transition hover:bg-cyan-500/25",children:"TikTok"})]})]}),(null==eJ?void 0:eJ.probes)&&tw?(0,n.jsxs)("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:[eJ.probes.srs?(()=>{var e,t,s,l,i,r,a;let o=null===(e=eJ.probes)||void 0===e?void 0:e.srs,c=null==o?void 0:null===(t=o.tcp)||void 0===t?void 0:t.reachable,d=null==o?void 0:null===(s=o.tcp_api)||void 0===s?void 0:s.reachable,x=null==o?void 0:o.http_ui,u=null==o?void 0:o.http,m=null==o?void 0:o.api_port,h=null!==(i=null==o?void 0:o.api_ok)&&void 0!==i?i:(null==u?void 0:u.http_code)===200,p=null==x?void 0:x.http_code;return(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.07] bg-zinc-950/40 p-4 backdrop-blur-sm",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-white",children:"SRS"}),(0,n.jsx)("span",{className:"rounded-full px-2 py-0.5 text-[10px] font-semibold ".concat(h?"bg-emerald-500/20 text-emerald-200 ring-1 ring-emerald-500/30":"bg-rose-500/15 text-rose-200 ring-1 ring-rose-500/25"),children:h?tC("API 正常","API OK"):tC("API 异常","API down")})]}),(0,n.jsxs)("p",{className:"mt-1 font-mono text-[11px] text-zinc-500",children:[":",null!==(r=null==o?void 0:o.port)&&void 0!==r?r:"—"," / API :",null!=m?m:"—"," \xb7 TCP ",c?"OK":"—"," \xb7 API TCP"," ",d?"OK":"—"]}),(0,n.jsxs)("p",{className:"mt-1 font-mono text-[11px] text-zinc-500",children:["API HTTP ",null!==(a=null==u?void 0:u.http_code)&&void 0!==a?a:"—"," \xb7 ",tC("根路径","root")," ",null!=p?p:"—",404===p?tC("(无首页不影响推流)"," (no index is OK for streaming)"):null]}),(0,n.jsxs)("p",{className:"mt-1 text-[11px] text-zinc-500",children:[tC("延迟","RTT")," ",(null==u?void 0:u.latency_ms)!=null?"".concat(u.latency_ms," ms"):(null==o?void 0:null===(l=o.tcp)||void 0===l?void 0:l.latency_ms)!=null?"".concat(o.tcp.latency_ms," ms"):"—"]}),!h&&(null==u?void 0:u.error)?(0,n.jsx)("p",{className:"mt-1 line-clamp-2 text-[10px] text-amber-200/80",children:u.error}):null]})})():null,eJ.probes.neko?(()=>{var e,t,s,l,i,r,a;let o=null===(e=eJ.probes)||void 0===e?void 0:e.neko,c=null==o?void 0:null===(t=o.tcp)||void 0===t?void 0:t.reachable,d=null==o?void 0:o.http,x=(null==o?void 0:o.instances)||[],u=null!==(l=null==o?void 0:o.running_count)&&void 0!==l?l:x.filter(e=>{var t;return null===(t=e.tcp)||void 0===t?void 0:t.reachable}).length,m=null!==(i=null==o?void 0:o.required_count)&&void 0!==i?i:x.length;return(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.07] bg-zinc-950/40 p-4 backdrop-blur-sm",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-white",children:"Neko Chromium"}),(0,n.jsxs)("span",{className:"rounded-full px-2 py-0.5 text-[10px] font-semibold ".concat(u>0?"bg-emerald-500/20 text-emerald-200 ring-1 ring-emerald-500/30":"bg-rose-500/15 text-rose-200 ring-1 ring-rose-500/25"),children:[u,"/",m||"—"," ",tC("在线","online")]})]}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("Docker 内 Chromium(非 Chrome 品牌);arm64/x86 同一镜像。","Chromium in Docker (not Chrome branding); multi-arch.")}),(0,n.jsxs)("p",{className:"mt-2 font-mono text-[11px] text-zinc-500",children:[":",null!==(r=null==o?void 0:o.port)&&void 0!==r?r:"—"," \xb7 TCP ",c?"OK":"—"," \xb7 HTTP ",null!==(a=null==d?void 0:d.http_code)&&void 0!==a?a:"—"]}),(0,n.jsxs)("p",{className:"mt-1 text-[11px] text-zinc-500",children:[tC("延迟","RTT")," ",(null==d?void 0:d.latency_ms)!=null?"".concat(d.latency_ms," ms"):(null==o?void 0:null===(s=o.tcp)||void 0===s?void 0:s.latency_ms)!=null?"".concat(o.tcp.latency_ms," ms"):"—"]}),x.length?(0,n.jsx)("div",{className:"mt-3 space-y-2",children:x.map(e=>{var t,s,l,i,r,a,o;return(0,n.jsxs)("div",{className:"flex items-center justify-between gap-3 rounded-lg border border-white/[0.05] bg-black/25 px-3 py-2",children:[(0,n.jsxs)("div",{className:"min-w-0",children:[(0,n.jsxs)("p",{className:"text-[11px] font-semibold text-zinc-200",children:["Neko ",null!==(r=e.id)&&void 0!==r?r:"?"]}),(0,n.jsxs)("p",{className:"font-mono text-[10px] text-zinc-500",children:[":",null!==(a=e.port)&&void 0!==a?a:"—"," \xb7 TCP ",(null===(t=e.tcp)||void 0===t?void 0:t.reachable)?"OK":"—"," \xb7 HTTP"," ",null!==(o=null===(s=e.http)||void 0===s?void 0:s.http_code)&&void 0!==o?o:"—"]})]}),(0,n.jsx)("span",{className:"shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold ".concat((null===(l=e.tcp)||void 0===l?void 0:l.reachable)?"bg-emerald-500/15 text-emerald-200 ring-1 ring-emerald-500/25":"bg-zinc-500/15 text-zinc-400 ring-1 ring-zinc-500/25"),children:(null===(i=e.tcp)||void 0===i?void 0:i.reachable)?tC("运行中","Running"):tC("未连通","Offline")})]},"".concat(e.id,"-").concat(e.port))})}):null,!(null==d?void 0:d.reachable)&&(null==d?void 0:d.error)?(0,n.jsx)("p",{className:"mt-1 line-clamp-2 text-[10px] text-amber-200/80",children:d.error}):null]})})():null]}):null]}):null,"services"===eK?(0,n.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-3",children:[((null==eJ?void 0:eJ.services)||[]).map((e,t)=>(0,n.jsxs)(l.E.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},transition:{delay:.04*t},whileHover:{y:-2},className:"rounded-2xl border border-white/[0.07] bg-gradient-to-b from-white/[0.05] to-transparent p-5",children:[(0,n.jsxs)("div",{className:"flex items-start justify-between gap-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-semibold text-white",children:e.label}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500 line-clamp-2",children:e.description})]}),(0,n.jsx)("span",{className:"shrink-0 rounded-full px-2.5 py-1 text-[10px] font-semibold ".concat(e4(e.running?"online":e.status)),children:e.running?tC("运行中","Running"):e.status})]}),e.detail?(0,n.jsx)("p",{className:"mt-2 text-[11px] leading-snug line-clamp-6 ".concat("skipped"===e.status?"text-slate-300/90":"text-amber-200/85"),children:e.detail}):null,"shellcrash"===e.service_id&&e.available&&!e.running?(0,n.jsx)("p",{className:"mt-2 text-[11px] text-zinc-500",children:tC("stopped 为常态:仅当需要透明代理 / 规则分流时再点 Start(或 systemctl enable --now shellcrash)。","Stopped is normal; Start only when you need the proxy (or enable shellcrash.service).")}):null,(0,n.jsxs)("div",{className:"mt-4 flex flex-wrap items-center gap-2",children:[e.url?(0,n.jsx)("a",{href:(0,ex.p)(e.url),target:"_blank",rel:"noreferrer",className:"rounded-lg bg-violet-500/15 px-3 py-1.5 text-xs font-medium text-violet-200 ring-1 ring-violet-500/25",children:tC("打开面板","Open panel")}):null,(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"start"),className:"rounded-lg bg-emerald-500/20 px-3 py-1.5 text-xs font-medium text-emerald-200 ring-1 ring-emerald-500/30 disabled:opacity-30",children:"Start"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"install"),className:"rounded-lg bg-sky-500/15 px-3 py-1.5 text-xs font-medium text-sky-200 ring-1 ring-sky-500/25 disabled:opacity-30",children:"Install"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"restart"),className:"rounded-lg bg-amber-500/15 px-3 py-1.5 text-xs font-medium text-amber-200 ring-1 ring-amber-500/25 disabled:opacity-30",children:"Restart"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"upgrade"),className:"rounded-lg bg-indigo-500/15 px-3 py-1.5 text-xs font-medium text-indigo-200 ring-1 ring-indigo-500/25 disabled:opacity-30",children:"Upgrade"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"stop"),className:"rounded-lg bg-rose-500/15 px-3 py-1.5 text-xs font-medium text-rose-200 ring-1 ring-rose-500/25 disabled:opacity-30",children:"Stop"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"uninstall"),className:"rounded-lg bg-zinc-500/15 px-3 py-1.5 text-xs font-medium text-zinc-200 ring-1 ring-zinc-500/25 disabled:opacity-30",children:"Uninstall"})]})]},e.service_id)),(null==eJ?void 0:null===(eh=eJ.services)||void 0===eh?void 0:eh.length)?null:(0,n.jsx)("p",{className:"text-sm text-zinc-500",children:tC("暂无服务数据","No services")})]}):null,"live_youtube"===eK?(0,n.jsx)(e0,{t:tC,busy:eQ,entries:tn,currentProc:ta,setCurrentProc:to,urlConfig:tc,setUrlConfig:td,onRunProcess:(e,t)=>void tA(e,t),onSaveUrlConfig:(e,t)=>tZ(e,t),fetchJson:tP,liveProcesses:ti.length?ti:null!==(eD=null==eJ?void 0:null===(ep=eJ.live)||void 0===ep?void 0:ep.processes)&&void 0!==eD?eD:[],notify:tR,quickLinks:tU,onNavigate:e=>eF(e)}):null,"live_tiktok"===eK?(0,n.jsx)(ez,{t:tC,busy:!!eQ,entries:tn,currentProc:ta,setCurrentProc:to,urlConfig:tc,setUrlConfig:td,onRunProcess:e=>void tA(e),onSaveUrlConfig:e=>tZ(e),onReplayGoLive:async(e,t)=>{let s=t.replace(/[,,|]/g,"_");await tZ("原画,".concat(e,",主播: ").concat(s)),await tA("start")},onCopy:tB,fetchJson:tP,apiPrefix:eA,quickLinks:tU,hdmiStatus:null==eJ?void 0:eJ.hdmi,notify:tR,onNavigate:e=>eF(e)}):null,"android"===eK?(0,n.jsx)(er,{t:tC,notify:tR,fetchJson:tP,apiBase:eA,busy:eQ,androidSerial:tm,setAndroidSerial:th,devices:(null==eJ?void 0:null===(eb=eJ.android)||void 0===eb?void 0:eb.devices)||[],adbAvailable:!!(null==eJ?void 0:null===(eg=eJ.android)||void 0===eg?void 0:eg.adb_available),apkPath:tx,setApkPath:tu,onAndroidAction:(e,t)=>tO(e,null!=t?t:{}),onCopy:tB,onRefreshDevices:()=>void tL()}):null,"network"===eK?(0,n.jsxs)("div",{className:"mx-auto max-w-7xl space-y-6",children:[(0,n.jsxs)("div",{className:"rounded-2xl border p-6 ".concat("light"===eH?"border-violet-200/90 bg-gradient-to-br from-violet-50 via-white to-fuchsia-50/80":"border-violet-500/25 bg-gradient-to-br from-violet-500/10 via-zinc-950/40 to-fuchsia-500/5"),children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold ".concat("light"===eH?"text-slate-900":"text-white"),children:[(0,n.jsx)(k.Z,{className:"h-4 w-4 ".concat("light"===eH?"text-violet-600":"text-violet-300")}),tC("ShellCrash 网络面板","ShellCrash panel")]}),(0,n.jsx)("p",{className:"mt-2 text-xs ".concat("light"===eH?"text-slate-600":"text-zinc-400"),children:tC("透明代理与规则分流直接在本页完成,无需跳转;流媒体与其它系统服务请在「服务」页管理。","Proxy rules and YAML editing are embedded here. Use Services for SRS/Neko/Chromium, etc.")}),(0,n.jsx)("div",{className:"mt-6 flex flex-col items-center gap-4 sm:flex-row sm:justify-center",children:[{tx:tC("互联网","Internet"),c:"from-cyan-400 to-blue-500"},{tx:"ShellCrash",c:"from-violet-500 to-fuchsia-500"},{tx:tC("本机 / 安卓","Host / Android"),c:"from-emerald-400 to-teal-500"}].map((e,t)=>(0,n.jsxs)("div",{className:"flex items-center gap-4",children:[(0,n.jsx)("div",{className:"flex h-16 w-28 items-center justify-center rounded-2xl bg-gradient-to-br ".concat(e.c," text-xs font-bold text-white shadow-lg"),children:e.tx}),t<2?(0,n.jsx)(h.Z,{className:"hidden h-5 w-5 sm:block ".concat("light"===eH?"text-slate-400":"text-zinc-600")}):null]},e.tx))})]}),(0,n.jsx)("div",{className:"overflow-hidden rounded-2xl border shadow-xl ".concat("light"===eH?"border-slate-200/90 bg-white shadow-slate-200/40":"border-white/[0.08] bg-zinc-950/50 shadow-black/30"),children:(0,n.jsx)("div",{className:"max-h-[min(78vh,56rem)] min-h-[22rem] overflow-y-auto overflow-x-hidden",children:(0,n.jsx)(P.d,{embeddedShellCrash:!0,portalLang:eZ})})})]}):null,"settings"===eK?(0,n.jsxs)("div",{className:"mx-auto max-w-lg space-y-6",children:[(0,n.jsx)("p",{className:"text-sm ".concat("light"===eH?"text-slate-600":"text-zinc-400"),children:tC("常用选项(本机偏好);完整文件与 JSON 编辑见下方链接。","Local preferences; full file/JSON editor via the link below.")}),(0,n.jsxs)("div",{className:"space-y-4 rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-5",children:[(0,n.jsxs)("label",{className:"flex cursor-pointer items-center justify-between gap-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("p",{className:"text-sm font-medium text-white",children:tC("总览自动刷新","Auto-refresh dashboard")}),(0,n.jsx)("p",{className:"text-[11px] text-zinc-500",children:"10s"})]}),(0,n.jsx)("input",{type:"checkbox",className:"h-5 w-5 accent-violet-500",checked:tv,onChange:e=>{let t=e.target.checked;ty(t);try{localStorage.setItem("livehub.autorefresh",t?"1":"0")}catch(e){}tR(t?tC("已开启刷新","Auto refresh on"):tC("已暂停刷新","Paused"))}})]}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center justify-between gap-4 border-t border-white/[0.06] pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("p",{className:"text-sm font-medium text-white",children:tC("总览显示 SRS / Neko 探针","Show SRS/Neko probes")}),(0,n.jsx)("p",{className:"text-[11px] text-zinc-500",children:tC("关闭可精简首页","Hide stream probe cards")})]}),(0,n.jsx)("input",{type:"checkbox",className:"h-5 w-5 accent-violet-500",checked:tw,onChange:e=>{let t=e.target.checked;tN(t);try{localStorage.setItem("livehub.showStreamProbes",t?"1":"0")}catch(e){}}})]})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/40 p-5",children:[(0,n.jsx)("p",{className:"text-xs font-semibold uppercase tracking-wider text-zinc-500",children:tC("配置快照","Config snapshot")}),(0,n.jsx)("p",{className:"mt-2 font-mono text-[11px] text-zinc-400",children:String((null==tp?void 0:tp.config_root)||"—")}),(0,n.jsxs)("p",{className:"mt-3 text-sm text-zinc-300",children:[tC("主机名","Hostname"),":"," ",(0,n.jsx)("span",{className:"font-mono text-violet-200",children:(()=>{var e,t,s;let n=null==tp?void 0:tp.system;return(null==n?void 0:null===(t=n.identity)||void 0===t?void 0:null===(e=t.hostname_alias)||void 0===e?void 0:e.trim())||((null==eJ?void 0:null===(s=eJ.stack)||void 0===s?void 0:s.mdns_host)||"").replace(/\.local$/i,"")||"—"})()})]}),(0,n.jsx)("div",{className:"mt-4 flex flex-wrap gap-2",children:null==tp?void 0:null===(ef=tp.services)||void 0===ef?void 0:ef.slice(0,8).map(e=>(0,n.jsxs)("span",{className:"rounded-full px-2.5 py-1 text-[10px] font-medium ".concat(e.enabled?"bg-emerald-500/15 text-emerald-200 ring-1 ring-emerald-500/25":"bg-zinc-500/15 text-zinc-400"),children:[e.id," ",e.enabled?"ON":"off"]},e.id))})]}),(0,n.jsxs)("a",{href:"/console?tab=config",className:"inline-flex w-full items-center justify-center gap-2 rounded-xl border py-3 text-sm transition ".concat("light"===eH?"border-slate-200 bg-slate-50 text-violet-700 hover:bg-slate-100":"border-white/10 bg-white/[0.05] text-violet-200 hover:bg-white/[0.08]"),children:[tC("完整配置中心(文件 / JSON)","Full config center (files / JSON)"),(0,n.jsx)(z.Z,{className:"h-4 w-4"})]})]}):null]},eK)})})]})]}),(0,n.jsx)(i.M,{children:eW?(0,n.jsx)(l.E.div,{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},className:"fixed inset-0 z-50 bg-black/60 backdrop-blur-sm lg:hidden",onClick:()=>eY(!1),children:(0,n.jsxs)(l.E.aside,{initial:{x:-280},animate:{x:0},exit:{x:-280},transition:{type:"spring",damping:28,stiffness:320},className:"absolute left-0 top-0 h-full w-[min(88vw,280px)] border-r border-white/10 bg-zinc-950 p-4 shadow-2xl",onClick:e=>e.stopPropagation(),children:[(0,n.jsx)("div",{className:"flex justify-end",children:(0,n.jsx)("button",{type:"button",onClick:()=>eY(!1),className:"rounded-lg p-2",children:(0,n.jsx)(S.Z,{className:"h-5 w-5"})})}),(0,n.jsx)("nav",{className:"mt-4 flex flex-col gap-1",children:tH.map(e=>{let t=e.icon,s=eK===e.id;return(0,n.jsxs)("button",{type:"button",onClick:()=>{eF(e.id),eY(!1)},"aria-current":s?"page":void 0,className:"flex items-center gap-3 rounded-xl px-3 py-3 text-left text-sm transition ".concat(s?"bg-white/[0.08] text-white shadow-inner shadow-white/5":"text-zinc-300 hover:bg-white/[0.04]"),children:[(0,n.jsx)(t,{className:"h-4 w-4 ".concat(s?"text-violet-300":"text-violet-400")}),tC(e.labelZh,e.labelEn)]},e.id)})})]})}):null})]})}}},function(e){e.O(0,[500,719,246,971,117,744],function(){return e(e.s=4578)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/d2ypp2/web-console/out/_next/static/chunks/app/page-3c5cf076d3a5e7c5.js b/d2ypp2/web-console/out/_next/static/chunks/app/page-3c5cf076d3a5e7c5.js new file mode 100644 index 0000000..5fccce4 --- /dev/null +++ b/d2ypp2/web-console/out/_next/static/chunks/app/page-3c5cf076d3a5e7c5.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{4578:function(e,t,s){Promise.resolve().then(s.bind(s,1499))},1499:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return e7}});var n=s(7437),l=s(6247),i=s(7586),r=s(4401),a=s(6137),o=s(4372),c=s(5901),d=s(3388),x=s(3420),u=s(8728),m=s(2023),h=s(407),p=s(6840),b=s(7226),g=s(5929),f=s(7945),v=s(1817),y=s(7168),w=s(4822),N=s(4428),j=s(1723),k=s(2926),z=s(7580),S=s(2489),_=s(2265);function C(e){let{tr:t}=e,l=(0,_.useRef)(null);return(0,_.useEffect)(()=>{let e;if(!l.current)return;let t=!1,n=0;return s.e(689).then(s.bind(s,1448)).then(s=>{if(t||!l.current)return;let i=l.current,r=Math.max(i.clientWidth,280),a=Math.max(i.clientHeight,200),o=new s.Scene,c=new s.PerspectiveCamera(48,r/a,.1,80);c.position.set(0,1.1,7.2);let d=new s.WebGLRenderer({antialias:!0,alpha:!0});d.setPixelRatio(Math.min(window.devicePixelRatio,2)),d.setSize(r,a),d.setClearColor(0,0),i.appendChild(d.domElement);let x=new s.HemisphereLight(16762092,4482815,.85);o.add(x);let u=new s.DirectionalLight(16777215,.9);u.position.set(4,8,6),o.add(u);let m=new s.PointLight(8189439,.6,20);m.position.set(-3,2,-2),o.add(m);let h=new s.Group,p=new s.Mesh(new s.BoxGeometry(3.2,.35,2.2),new s.MeshStandardMaterial({color:2762048,metalness:.15,roughness:.55}));p.position.y=-.85,h.add(p);let b=new s.Mesh(new s.TorusGeometry(.72,.09,12,48),new s.MeshStandardMaterial({color:16724821,emissive:4456465,metalness:.35,roughness:.25}));b.rotation.x=Math.PI/2,b.position.set(-.85,.15,.2),h.add(b);let g=new s.Mesh(new s.ConeGeometry(.35,.5,3),new s.MeshStandardMaterial({color:16777215,emissive:2236962,metalness:.2,roughness:.3}));g.rotation.z=-Math.PI/2,g.rotation.y=Math.PI,g.position.set(-.55,.18,.2),h.add(g);let f=new s.Mesh(new s.CylinderGeometry(.22,.28,.95,20),new s.MeshStandardMaterial({color:2487534,emissive:340024,metalness:.25,roughness:.35}));f.position.set(1.05,.35,-.15),f.rotation.z=.12,h.add(f);let v=new s.Mesh(new s.SphereGeometry(.26,16,16),new s.MeshStandardMaterial({color:16657493,emissive:2229520,metalness:.2,roughness:.4}));v.position.set(1.05,.92,-.15),h.add(v);let y=new s.BufferGeometry,w=new Float32Array(360);for(let e=0;e<120;e++)w[3*e]=(Math.random()-.5)*14,w[3*e+1]=(Math.random()-.3)*8,w[3*e+2]=(Math.random()-.5)*8-2;y.setAttribute("position",new s.BufferAttribute(w,3));let N=new s.Points(y,new s.PointsMaterial({color:16777215,size:.06,transparent:!0,opacity:.7}));o.add(N),o.add(h);let j=performance.now(),k=()=>{if(t)return;n=requestAnimationFrame(k);let e=(performance.now()-j)/1e3;h.rotation.y=.25*Math.sin(.35*e)+.12*e,h.position.y=.06*Math.sin(.9*e),b.rotation.z=.4*e,N.rotation.y=.02*e,d.render(o,c)};k();let z=new ResizeObserver(()=>{if(!l.current||t)return;let e=Math.max(l.current.clientWidth,280),s=Math.max(l.current.clientHeight,200);c.aspect=e/s,c.updateProjectionMatrix(),d.setSize(e,s)});z.observe(i),e=()=>{cancelAnimationFrame(n),z.disconnect(),d.dispose(),y.dispose(),d.domElement.parentNode===i&&i.removeChild(d.domElement)}}),()=>{t=!0,cancelAnimationFrame(n),null==e||e()}},[]),(0,n.jsxs)("div",{className:"flex h-full min-h-[14rem] flex-col",children:[(0,n.jsx)("p",{className:"mb-2 px-1 text-[10px] font-medium uppercase tracking-wider text-fuchsia-200/80",children:t("直播工作室 \xb7 3D","Live studio \xb7 3D")}),(0,n.jsx)("div",{ref:l,className:"relative min-h-[12rem] flex-1 overflow-hidden rounded-xl bg-gradient-to-b from-fuchsia-950/40 to-cyan-950/20 ring-1 ring-white/10"})]})}var R=s(9170),P=s(2246),L=s(4286),M=s(4794),T=s(221),U=s(8867),E=s(8124),I=s(2101),D=s(3651),A=s(9985),Z=s(6362),O=s(3468),H=s(6443),B=s(5287),K=s(3276),F=s(9227),W=s(257),Y=s(1387);class J{reset(){if(this.buf=new Uint8Array(0),this.sps=null,this.pps=null,this.configured=!1,this.configuring=!1,this.ts=0,this.decoder){try{this.decoder.close()}catch(e){}this.decoder=null}}push(e){let t=new Uint8Array(e.byteLength);t.set(new Uint8Array(e)),this.buf=function(e,t){let s=new Uint8Array(e.length+t.length);return s.set(e,0),s.set(t,e.length),s}(this.buf,t),this.drainAvcc()}drainAvcc(){let e=this.buf,t=0;for(;t+4<=e.length;){var s;let n=e[s=t]<<24|e[s+1]<<16|e[s+2]<<8|e[s+3];if(n<=0||n>6291456){this.buf=new Uint8Array(e.subarray(t+1)),t=0;continue}if(t+4+n>e.length)break;let l=e.subarray(t+4,t+4+n);t+=4+n,this.handleNal(l)}t>0&&(this.buf=new Uint8Array(e.subarray(t)))}handleNal(e){if(e.length<2)return;let t=31&e[0];if(7===t?this.sps=new Uint8Array(e):8===t&&(this.pps=new Uint8Array(e)),this.sps&&this.pps&&!this.configured&&!this.configuring&&this.configure(),!this.configured||!this.decoder||1!==t&&5!==t&&7!==t&&8!==t||7===t||8===t)return;let s=new Uint8Array(4+e.length);new DataView(s.buffer).setUint32(0,e.length,!1),s.set(e,4);try{let e=new EncodedVideoChunk({type:5===t?"key":"delta",timestamp:this.ts,data:s});this.ts+=33333,this.decoder.decode(e)}catch(e){this.onDecodeError(e.message||String(e))}}async configure(){if(this.sps&&this.pps&&!this.configured&&!this.configuring){this.configuring=!0;try{let e=function(e,t){let s=e.subarray(1),n=t.subarray(1),l=new Uint8Array(11+s.length+3+n.length),i=0;return l[i++]=1,l[i++]=e[1],l[i++]=e[2],l[i++]=e[3],l[i++]=255,l[i++]=225,l[i++]=s.length>>8&255,l[i++]=255&s.length,l.set(s,i),i+=s.length,l[i++]=1,l[i++]=n.length>>8&255,l[i++]=255&n.length,l.set(n,i),l}(this.sps,this.pps),t=function(e){let t=e=>e.toString(16).padStart(2,"0").toUpperCase();return"avc1.".concat(t(e[1])).concat(t(e[2])).concat(t(e[3]))}(this.sps),s=new VideoDecoder({output:e=>{var t;let s=this.canvas.getContext("2d");if(!s){e.close();return}(this.canvas.width!==e.displayWidth||this.canvas.height!==e.displayHeight)&&(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),s.drawImage(e,0,0),e.close(),null===(t=this.onFrame)||void 0===t||t.call(this)},error:e=>this.onDecodeError(String(e.message||e))});await s.configure({codec:t,description:e,optimizeForLatency:!0}),this.decoder=s,this.configured=!0}catch(e){this.onDecodeError(e.message||String(e))}finally{this.configuring=!1}}}constructor(e,t,s){this.canvas=e,this.onDecodeError=t,this.onFrame=s,this.buf=new Uint8Array(0),this.decoder=null,this.configured=!1,this.configuring=!1,this.ts=0,this.sps=null,this.pps=null}}function G(){return"undefined"!=typeof VideoDecoder&&"undefined"!=typeof VideoFrame}let V="live-hub-adb-bookmarks-v1";function q(e,t,s){let n,l,i,r;let a=e.getBoundingClientRect(),o=e.width,c=e.height;if(!o||!c)return null;let d=a.width/a.height,x=o/c;x>d?(n=a.width,l=a.width/x,i=0,r=(a.height-l)/2):(l=a.height,n=a.height*x,i=(a.width-n)/2,r=0);let u=t-a.left-i,m=s-a.top-r;return u<0||m<0||u>n||m>l?null:{x:Math.max(0,Math.min(o-1,Math.round(u/n*o))),y:Math.max(0,Math.min(c-1,Math.round(m/l*c)))}}function X(e,t,s){let n,l,i,r;let a=e.getBoundingClientRect(),o=e.naturalWidth,c=e.naturalHeight;if(!o||!c)return null;let d=a.width/a.height,x=o/c;x>d?(n=a.width,l=a.width/x,i=0,r=(a.height-l)/2):(l=a.height,n=a.height*x,i=(a.width-n)/2,r=0);let u=t-a.left-i,m=s-a.top-r;return u<0||m<0||u>n||m>l?null:{x:Math.max(0,Math.min(o-1,Math.round(u/n*o))),y:Math.max(0,Math.min(c-1,Math.round(m/l*c)))}}let $=[0,280,450,700,1100];function Q(e){switch(e){case"usb":return{Icon:I.Z,zh:"USB",en:"USB",cls:"bg-amber-500/20 text-amber-100 ring-amber-500/35"};case"tcp":return{Icon:k.Z,zh:"网络",en:"TCP",cls:"bg-cyan-500/20 text-cyan-100 ring-cyan-500/35"};case"emulator":return{Icon:D.Z,zh:"模拟器",en:"Emu",cls:"bg-fuchsia-500/20 text-fuchsia-100 ring-fuchsia-500/35"};default:return{Icon:d.Z,zh:"?",en:"?",cls:"bg-zinc-600/30 text-zinc-400"}}}let ee="https://github.com/Genymobile/scrcpy",et="https://github.com/viarotel-org/escrcpy";function es(e,t){let s=t.startsWith("/")?t:"/".concat(t),n=(e||"").trim().replace(/\/$/,"");return n?"".concat(n).concat(s):s}function en(e){var t;let{t:s,apiBase:l,fetchJson:i,serial:r,devices:a,setSerial:o,adbAvailable:c,lock:x,overview:u,onAndroidAction:h,notify:p,onRefreshDevices:b}=e,[g,f]=(0,_.useState)(0),[v,w]=(0,_.useState)(450),[N,j]=(0,_.useState)(!1),[k,z]=(0,_.useState)(null),[S,C]=(0,_.useState)(null),[R,P]=(0,_.useState)(!0),[L,M]=(0,_.useState)(""),[T,U]=(0,_.useState)(""),[E,I]=(0,_.useState)("37777"),[D,en]=(0,_.useState)(""),[el,ei]=(0,_.useState)(!1),[er,ea]=(0,_.useState)([]),[eo,ec]=(0,_.useState)(!1),[ed,ex]=(0,_.useState)(null),[eu,em]=(0,_.useState)(!1),[eh,ep]=(0,_.useState)(null),[eb,eg]=(0,_.useState)(null),[ef,ev]=(0,_.useState)(!0),ey=(0,_.useRef)(null),ew=(0,_.useRef)(null),eN=(0,_.useRef)(null),ej=(0,_.useRef)(null),ek=(0,_.useRef)(null),ez=(0,_.useRef)(null),eS=(0,_.useRef)(0),e_=(0,_.useRef)(!1),eC=(0,_.useRef)(null),eR=(0,_.useRef)(!1),eP=null===(t=a.find(e=>e.serial===r))||void 0===t?void 0:t.transport,eL=v>0,eM=r?"".concat(es(l,"/android/screenshot"),"?serial=").concat(encodeURIComponent(r),"&ts=").concat(g).concat(eL?"&fast=1":""):"",eT=(0,_.useCallback)(()=>{f(e=>e+1)},[]),eU=(0,_.useCallback)(()=>{null!=eC.current&&(window.clearTimeout(eC.current),eC.current=null)},[]);(0,_.useEffect)(()=>{let e=()=>ev("visible"===document.visibilityState);return e(),document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[]),(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(V);if(e){let t=JSON.parse(e);Array.isArray(t)&&ea(t.map(String).filter(Boolean).slice(0,24))}}catch(e){}},[]);let eE=e=>{let t=e.trim();if(!t)return;let n=[t,...er.filter(e=>e!==t)].slice(0,16);ea(n);try{window.localStorage.setItem(V,JSON.stringify(n))}catch(e){}p(s("已保存快捷地址","Saved quick address"))};(0,_.useEffect)(()=>{if(!r||!c){C(null);return}let e=!1;return(async()=>{try{let t=await (0,Y.N)("".concat(es(l,"/android/display_metrics"),"?serial=").concat(encodeURIComponent(r)));if(e)return;"number"==typeof t.width&&"number"==typeof t.height&&C({width:t.width,height:t.height})}catch(e){}})(),()=>{e=!0}},[l,c,r]),(0,_.useEffect)(()=>{if(!c||!r||v<=0||eo||!ef)return;let e=window.setInterval(()=>f(e=>e+1),v);return()=>clearInterval(e)},[c,v,ef,r,eo]),(0,_.useEffect)(()=>{ef&&c&&r&&!eo&&eT()},[c,eT,ef,r,eo]),(0,_.useEffect)(()=>{if(!c){eg(null);return}let e=!1;return(async()=>{try{let t=await (0,Y.N)(es(l,"/android/scrcpy/info"));e||eg(t)}catch(e){}})(),()=>{e=!0}},[l,c]),(0,_.useEffect)(()=>{eo||ep(null)},[eo]),(0,_.useEffect)(()=>{ex(null),e_.current=!1},[r]),(0,_.useEffect)(()=>{let e=a.find(e=>e.serial===r),t=!!(r&&ed===r);if(c&&r&&(null==e?void 0:e.state)==="device"&&(null==eb?void 0:eb.server_jar)&&G()&&!t){ec(!0),w(0);return}if(t||!r||!c||eb&&!eb.server_jar||!G()||e&&"device"!==e.state){ec(!1);return}},[r,a,c,eb,ed]),(0,_.useEffect)(()=>{if(!eo||!r||!c){var e,t;eU(),e_.current=!0,eR.current=!1,null===(e=ej.current)||void 0===e||e.close(),ej.current=null,null===(t=ek.current)||void 0===t||t.reset(),ek.current=null,em(!1);return}if(!G()){ep(s("当前浏览器不支持 WebCodecs H.264","WebCodecs H.264 not supported in this browser")),ec(!1);return}let n=eN.current;if(!n)return;let i=e=>{var t;eU(),e_.current=!0,null===(t=ej.current)||void 0===t||t.close(),ep(e),ec(!1),w(450),ex(r),window.setTimeout(()=>eT(),120)},a=new J(n,e=>i("".concat(s("实时画面解码失败,已切回截图模式","Live stream decode failed, using screenshot mode"),": ").concat(e)),()=>{eR.current=!0,eU()});ek.current=a,e_.current=!1,eR.current=!1;let o=new WebSocket(function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1920,n=(function(e){let t=(e||"").trim();if(t)try{let e=new URL(t,window.location.href),s="https:"===e.protocol?"wss:":"ws:";return"".concat(s,"//").concat(e.host)}catch(e){}let s=void 0!==W&&W.env.NEXT_PUBLIC_API_URL?String(W.env.NEXT_PUBLIC_API_URL).trim():"";if(s)try{let e=new URL(s,window.location.href),t="https:"===e.protocol?"wss:":"ws:";return"".concat(t,"//").concat(e.host)}catch(e){}let n=window.location.port;if("3000"===n||"3001"===n){let e=window.location.hostname||"127.0.0.1";return"ws://".concat(e,":").concat("8001")}let{protocol:l,host:i}=window.location;return"".concat("https:"===l?"wss:":"ws:","//").concat(i)})(e).replace(/\/$/,""),l=new URLSearchParams({serial:t,max_size:String(s)});return"".concat(n,"/android/scrcpy/ws?").concat(l.toString())}(l,r));return ej.current=o,o.binaryType="arraybuffer",o.onopen=()=>{em(!0),ep(null),eU(),eC.current=window.setTimeout(()=>{eR.current||i(s("实时画面无首帧,已切回截图模式","No first live frame, using screenshot mode"))},5200)},o.onmessage=e=>{var t;if("string"==typeof e.data){try{let t=JSON.parse(e.data);t.error&&ep(t.error)}catch(e){}return}null===(t=ek.current)||void 0===t||t.push(e.data)},o.onerror=()=>{ep(s("WebSocket 异常","WebSocket error"))},o.onclose=()=>{var e;em(!1),null===(e=ek.current)||void 0===e||e.reset(),ek.current=null,eU(),eo&&!e_.current&&i(s("实时画面连接失败,已切回截图模式","Live stream failed, using screenshot mode"))},()=>{eU(),e_.current=!0,eR.current=!1,o.close(),ej.current=null,a.reset(),ek.current===a&&(ek.current=null)}},[eo,r,c,l,eT,eU,s]),(0,_.useEffect)(()=>{r&&c&&(eS.current=0,f(e=>e+1))},[r,c]);let eI=async()=>{let e=L.trim();if(!e){p(s("填写 host:port","Enter host:port"));return}ei(!0);try{let t=await i("/android/connect",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({address:e})});p(t.message||(t.ok?"OK":s("连接结果见日志","See message"))),b(),eT()}catch(e){p(e.message)}finally{ei(!1)}},eD=async e=>{ei(!0);try{let t=await i("/android/disconnect",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({address:e})});p(t.message||"OK"),b()}catch(e){p(e.message)}finally{ei(!1)}},eA=async()=>{let e=T.trim(),t=parseInt(E,10)||37777,n=D.trim();if(!e||!n){p(s("填写配对 IP 与码","Host + code required"));return}ei(!0);try{let l=await i("/android/pair",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({host:e,port:t,code:n})});p(l.message||(l.ok?s("配对成功后再点连接","Paired — now Connect"):"pair"))}catch(e){p(e.message)}finally{ei(!1)}},eZ=async e=>{if(!R||x||!c||!r)return;let t=ew.current;if(!t)return;let n=X(t,e.clientX,e.clientY);if(!n)return;let l=Date.now(),i=ey.current;i&&l-i.t<320&&28>Math.abs(i.x-n.x)&&28>Math.abs(i.y-n.y)?(ey.current=null,await h("double_tap",{x:n.x,y:n.y}),p(s("双击","Double tap"))):(ey.current={t:l,x:n.x,y:n.y},await h("tap",{x:n.x,y:n.y})),eT()},eO=async e=>{if(e.preventDefault(),x||!c||!r)return;let t=ew.current;if(!t)return;let n=X(t,e.clientX,e.clientY);n&&(await h("long_press",{x:n.x,y:n.y,duration:720}),p(s("长按","Long press")),eT())},eH=async e=>{if(!R||x||!c||!r)return;let t=eN.current;if(!t)return;let n=q(t,e.clientX,e.clientY);if(!n)return;let l=Date.now(),i=ey.current;i&&l-i.t<320&&28>Math.abs(i.x-n.x)&&28>Math.abs(i.y-n.y)?(ey.current=null,await h("double_tap",{x:n.x,y:n.y}),p(s("双击","Double tap"))):(ey.current={t:l,x:n.x,y:n.y},await h("tap",{x:n.x,y:n.y})),eo||eT()},eB=async e=>{if(e.preventDefault(),x||!c||!r)return;let t=eN.current;if(!t)return;let n=q(t,e.clientX,e.clientY);n&&(await h("long_press",{x:n.x,y:n.y,duration:720}),p(s("长按","Long press")),eo||eT())};if(!c)return(0,n.jsx)("div",{className:"rounded-2xl border border-amber-500/25 bg-amber-500/[0.06] p-6 text-center text-sm text-amber-200/90",children:s("宿主机未安装 adb,无法使用 Live 控制台。","adb is required for the Live console.")});let eK=Q(eP),eF=eK.Icon;return(0,n.jsxs)("div",{className:"space-y-5",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-sky-500/20 bg-gradient-to-br from-sky-500/[0.08] via-zinc-950/80 to-zinc-900/90 p-4 ring-1 ring-white/[0.05]",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2 border-b border-white/[0.06] pb-3",children:[(0,n.jsx)(A.Z,{className:"h-4 w-4 text-sky-400"}),(0,n.jsx)("h4",{className:"text-sm font-semibold text-white",children:s("链路管理","Link manager")}),(0,n.jsx)("span",{className:"text-[10px] text-zinc-500",children:s("USB / Redroid :5555 / 无线调试(先配对再连接)","USB \xb7 Redroid :5555 \xb7 wireless (pair then connect)")})]}),(0,n.jsxs)("div",{className:"mt-3 grid gap-3 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"space-y-2 rounded-xl border border-white/[0.06] bg-black/35 p-3",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"adb connect"}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("input",{className:"min-w-[12rem] flex-1 rounded-lg border border-white/10 bg-black/50 px-3 py-2 font-mono text-xs text-zinc-200",placeholder:"192.168.1.10:5555",value:L,onChange:e=>M(e.target.value),onKeyDown:e=>"Enter"===e.key&&void eI()}),(0,n.jsx)("button",{type:"button",disabled:el||x,onClick:()=>void eI(),className:"rounded-lg bg-sky-500/25 px-3 py-2 text-xs font-semibold text-sky-100 ring-1 ring-sky-400/40",children:el?"…":"Connect"}),(0,n.jsx)("button",{type:"button",disabled:el||x||!L.trim(),onClick:()=>eE(L),className:"rounded-lg border border-white/10 px-3 py-2 text-xs text-zinc-400 hover:text-zinc-200",children:s("存书签","Pin")})]}),er.length?(0,n.jsx)("div",{className:"flex flex-wrap gap-1.5 pt-1",children:er.map(e=>(0,n.jsx)("button",{type:"button",className:"rounded-md bg-white/[0.06] px-2 py-0.5 font-mono text-[10px] text-zinc-400 hover:bg-white/10",onClick:()=>M(e),children:e},e))}):null,(0,n.jsxs)("div",{className:"flex flex-wrap gap-2 pt-2",children:[(0,n.jsx)("button",{type:"button",disabled:el||x||!r,onClick:()=>void eD(r),className:"rounded-lg border border-rose-500/30 bg-rose-500/10 px-2.5 py-1.5 text-[10px] text-rose-200",children:s("断开当前 TCP","Disconnect current")}),(0,n.jsx)("button",{type:"button",disabled:el||x,onClick:()=>void eD(""),className:"rounded-lg border border-white/10 px-2.5 py-1.5 text-[10px] text-zinc-500 hover:text-zinc-300",children:s("断开全部 TCP","Disconnect all TCP")}),(0,n.jsxs)("button",{type:"button",disabled:el||x,onClick:()=>{b(),eT(),p(s("已刷新设备列表","Devices refreshed"))},className:"inline-flex items-center gap-1 rounded-lg border border-white/10 px-2.5 py-1.5 text-[10px] text-zinc-400",children:[(0,n.jsx)(y.Z,{className:"h-3 w-3"}),"ADB list"]})]})]}),(0,n.jsxs)("div",{className:"space-y-2 rounded-xl border border-white/[0.06] bg-black/35 p-3",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"adb pair(无线调试)"}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("input",{className:"w-32 rounded-lg border border-white/10 bg-black/50 px-2 py-1.5 font-mono text-xs",placeholder:"IP",value:T,onChange:e=>U(e.target.value)}),(0,n.jsx)("input",{className:"w-20 rounded-lg border border-white/10 bg-black/50 px-2 py-1.5 font-mono text-xs",placeholder:"port",value:E,onChange:e=>I(e.target.value)}),(0,n.jsx)("input",{className:"min-w-[6rem] flex-1 rounded-lg border border-white/10 bg-black/50 px-2 py-1.5 font-mono text-xs tracking-widest",placeholder:"123456",value:D,onChange:e=>en(e.target.value)}),(0,n.jsx)("button",{type:"button",disabled:el||x,onClick:()=>void eA(),className:"rounded-lg bg-violet-500/20 px-3 py-1.5 text-xs text-violet-100 ring-1 ring-violet-400/35",children:"Pair"})]}),(0,n.jsx)("p",{className:"text-[10px] leading-relaxed text-zinc-600",children:s("手机上「无线调试」会显示配对端口与 6 位码;配对成功后用上方 connect 连接 adb 显示的 IP:5555。","Use the pairing port + 6-digit code from Wireless debugging; then connect to the listed adb IP:5555.")})]})]})]}),(0,n.jsxs)("div",{className:"relative overflow-hidden rounded-3xl border border-emerald-500/25 bg-gradient-to-br from-emerald-500/[0.12] via-zinc-950/90 to-violet-500/[0.08] p-1 shadow-2xl shadow-emerald-900/20 ring-1 ring-white/[0.06]",children:[(0,n.jsx)("div",{className:"pointer-events-none absolute -right-20 -top-20 h-56 w-56 rounded-full bg-emerald-500/10 blur-3xl","aria-hidden":!0}),(0,n.jsxs)("div",{className:"relative rounded-[1.35rem] border border-white/[0.06] bg-zinc-950/80 p-4 backdrop-blur-sm",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",children:[(0,n.jsxs)("div",{className:"flex items-start gap-3",children:[(0,n.jsx)("div",{className:"flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-emerald-400/30 to-violet-500/25 ring-1 ring-white/10",children:(0,n.jsx)(m.Z,{className:"h-6 w-6 text-emerald-200"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-base font-semibold tracking-tight text-white",children:s("无人直播系统 \xb7 ADB 云控台","Unmanned Live System \xb7 ADB farm console")}),(0,n.jsxs)("p",{className:"mt-1 max-w-xl text-[11px] leading-relaxed text-zinc-500",children:[s("统一适配 USB / Redroid / 无线 adb:已授权设备默认走官方 scrcpy-server 的 WebSocket H.264 真流(与桌面 ","USB / Redroid / wireless adb: authorized devices default to official scrcpy-server WebSocket H.264 (same stack as "),(0,n.jsx)("a",{href:et,target:"_blank",rel:"noreferrer",className:"text-emerald-300/90 underline-offset-2 hover:underline",children:"escrcpy"}),s(" / "," / "),(0,n.jsx)("a",{href:ee,target:"_blank",rel:"noreferrer",className:"text-emerald-300/90 underline-offset-2 hover:underline",children:"scrcpy"}),s(");无 jar 或关闭真流时用截图。","); PNG screenshot when jar missing or stream off.")]})]})]}),(0,n.jsxs)("div",{className:"flex shrink-0 flex-col gap-1.5 self-start sm:flex-row",children:[(0,n.jsxs)("a",{href:et,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-xl border border-white/10 bg-white/[0.04] px-3 py-2 text-[11px] font-medium text-zinc-300 hover:bg-white/[0.07]",children:["escrcpy",(0,n.jsx)(Z.Z,{className:"h-3.5 w-3.5 opacity-70"})]}),(0,n.jsxs)("a",{href:ee,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-xl border border-white/10 bg-white/[0.04] px-3 py-2 text-[11px] font-medium text-zinc-300 hover:bg-white/[0.07]",children:["scrcpy",(0,n.jsx)(Z.Z,{className:"h-3.5 w-3.5 opacity-70"})]})]})]}),a.length>0?(0,n.jsxs)("div",{className:"mt-5",children:[(0,n.jsxs)("p",{className:"mb-2 flex items-center gap-2 text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:[(0,n.jsx)(O.Z,{className:"h-3.5 w-3.5"}),s("设备矩阵","Device matrix")]}),(0,n.jsx)("div",{className:"flex gap-2 overflow-x-auto pb-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",children:a.map(e=>{let t="device"===e.state,l=r===e.serial,i=Q(e.transport),a=i.Icon;return(0,n.jsxs)("button",{type:"button",onClick:()=>o(e.serial),className:"flex min-w-[9rem] flex-col rounded-xl border px-3 py-2 text-left transition ".concat(l?"border-emerald-500/50 bg-emerald-500/15 ring-1 ring-emerald-400/30":"border-white/10 bg-black/30 hover:border-white/20"),children:[(0,n.jsxs)("span",{className:"flex items-center gap-1.5 text-xs font-medium text-zinc-200",children:[(0,n.jsx)(d.Z,{className:"h-3.5 w-3.5 text-emerald-400/80"}),(0,n.jsx)("span",{className:"truncate",children:e.model||e.serial.slice(0,10)})]}),(0,n.jsx)("span",{className:"mt-0.5 truncate font-mono text-[9px] text-zinc-600",children:e.serial}),(0,n.jsxs)("div",{className:"mt-1 flex flex-wrap gap-1",children:[(0,n.jsxs)("span",{className:"inline-flex items-center gap-0.5 rounded-md px-1.5 py-0.5 text-[9px] font-semibold ring-1 ".concat(i.cls),children:[(0,n.jsx)(a,{className:"h-2.5 w-2.5"}),s(i.zh,i.en)]}),(0,n.jsx)("span",{className:"rounded-md px-1.5 py-0.5 text-[9px] font-semibold ".concat(t?"bg-emerald-500/20 text-emerald-200":"bg-zinc-600/30 text-zinc-500"),children:e.state})]})]},e.serial)})})]}):null,(0,n.jsxs)("div",{className:"mt-6 grid gap-6 xl:grid-cols-12",children:[(0,n.jsxs)("div",{className:"xl:col-span-8",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2 border-b border-white/[0.06] pb-3",children:[(0,n.jsx)("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:s("刷新间隔","Interval")}),$.map(e=>(0,n.jsx)("button",{type:"button",onClick:()=>w(e),className:"rounded-lg px-2.5 py-1 text-[10px] font-semibold transition ".concat(v===e?"bg-violet-500/25 text-violet-100 ring-1 ring-violet-400/35":"bg-black/30 text-zinc-500 hover:text-zinc-300"),children:0===e?s("手动","Manual"):"".concat(e,"ms")},e)),(0,n.jsxs)("span",{className:"ml-1 inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-[9px] font-medium ring-1 ".concat(eK.cls),children:[(0,n.jsx)(eF,{className:"h-3 w-3"}),"tcp"===eP?s("建议 ≥450ms","Suggest ≥450ms"):s("可试 280ms","Try 280ms")]}),(0,n.jsxs)("button",{type:"button",disabled:x,onClick:()=>void eT(),className:"ml-auto inline-flex items-center gap-1 rounded-lg border border-white/10 bg-white/[0.05] px-2.5 py-1 text-[10px] text-zinc-300 hover:bg-white/[0.08]",children:[(0,n.jsx)(y.Z,{className:"h-3 w-3 ".concat(N?"animate-spin":"")}),s("下一帧","Next frame")]}),(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>void h("wake"),className:"rounded-lg bg-amber-500/20 px-2.5 py-1 text-[10px] font-semibold text-amber-100 ring-1 ring-amber-500/30",children:"Wake"}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-1.5 text-[10px] text-zinc-400",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/50",checked:R,onChange:e=>P(e.target.checked)}),(0,n.jsx)(H.Z,{className:"h-3 w-3"}),s("点按穿透","Tap-through")]}),(0,n.jsxs)("button",{type:"button",disabled:x||!r||!(null==eb?void 0:eb.server_jar),title:eb&&!eb.server_jar&&eb.hint_zh?eb.hint_zh:s("官方 scrcpy-server + WebSocket H.264","Official scrcpy-server + WebSocket H.264"),onClick:()=>{ec(e=>{let t=!e;return t?(ex(null),p(s("已开启实时画面(H.264 WebSocket)","Live H.264 WebSocket stream on"))):(r&&ex(r),p(s("已关闭实时画面(将使用截图)","Live stream off — screenshot mode"))),t})},className:"inline-flex items-center gap-1 rounded-lg border px-2.5 py-1 text-[10px] font-semibold transition ".concat(eo?"border-cyan-400/50 bg-cyan-500/20 text-cyan-100 ring-1 ring-cyan-400/35":"border-white/10 bg-black/30 text-zinc-400 hover:text-zinc-200"),children:[(0,n.jsx)(B.Z,{className:"h-3 w-3"}),eo?s("关闭真流","Stop WS"):s("实时画面","Live H.264")]})]}),eb&&!eb.server_jar?(0,n.jsxs)("p",{className:"mt-2 text-[10px] text-amber-200/80",children:[s("未检测到 scrcpy-server:启动时会自动拉取;内网可在 runtime.env 配置 SCRCPY_SERVER_DOWNLOAD_URL(支持 {tag})。","scrcpy-server missing: auto-fetched on startup; set SCRCPY_SERVER_DOWNLOAD_URL ({tag}) for mirrors."),eb.server_version?" (".concat(s("期望版本","version")," ").concat(eb.server_version,")"):null]}):null,(0,n.jsx)("p",{className:"mt-2 text-[10px] text-zinc-600",children:s("快捷键(镜像区聚焦时):H Home \xb7 B Back \xb7 R 多任务 \xb7 W 唤醒 \xb7 M 菜单","Hotkeys (mirror focused): H Home \xb7 B Back \xb7 R Recents \xb7 W Wake \xb7 M Menu")}),(0,n.jsxs)("div",{className:"relative mx-auto mt-4 max-h-[min(78vh,720px)] min-h-[280px]",children:[r?(0,n.jsxs)("div",{ref:ez,tabIndex:0,onKeyDown:e=>{if(!r||x)return;let t=e.target.tagName;if("INPUT"===t||"TEXTAREA"===t||"SELECT"===t)return;let s={h:["key",{keycode:"3"}],b:["key",{keycode:"4"}],r:["key",{keycode:"187"}],w:["wake",void 0],m:["key",{keycode:"82"}]}[e.key.toLowerCase()];s&&(e.preventDefault(),(async()=>{await h(s[0],s[1]),eo||eT()})())},className:"relative flex justify-center outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/50",children:[(0,n.jsxs)("div",{className:"relative rounded-[2rem] border-[10px] border-zinc-800 bg-black shadow-inner shadow-black/80 ring-1 ring-white/10",style:{maxHeight:"min(72vh, 680px)"},children:[(0,n.jsx)("div",{className:"absolute left-1/2 top-0 z-10 h-5 w-24 -translate-x-1/2 rounded-b-xl bg-black/80"}),eo?(0,n.jsx)("canvas",{ref:eN,className:"max-h-[min(72vh,680px)] w-auto max-w-full rounded-[1.35rem] object-contain ".concat(R?"cursor-crosshair":"cursor-default"),draggable:!1,onClick:eH,onContextMenu:eB}):(0,n.jsx)("img",{ref:ew,src:eM||void 0,alt:"device",className:"max-h-[min(72vh,680px)] w-auto max-w-full rounded-[1.35rem] object-contain ".concat(R?"cursor-crosshair":"cursor-default"),draggable:!1,onLoadStart:()=>{j(!0)},onLoad:()=>{j(!1),eS.current=0,z(null)},onError:()=>{j(!1),eS.current+=1,eS.current<=3?(z(null),window.setTimeout(()=>eT(),380+200*eS.current)):z(s("截图连续失败:检查 USB 授权 / 无线是否断开 / Redroid 端口","Screenshot failed repeatedly"))},onClick:eZ,onContextMenu:eO})]}),eu?(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1 rounded-full bg-cyan-500/90 px-2 py-0.5 text-[9px] font-bold text-cyan-950 shadow-lg",children:[(0,n.jsx)(B.Z,{className:"h-3 w-3"}),"SCRCPY\xb7WS"]}):v>0&&!eo?(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1 rounded-full bg-emerald-500/90 px-2 py-0.5 text-[9px] font-bold text-emerald-950 shadow-lg",children:[(0,n.jsx)(K.Z,{className:"h-3 w-3"}),"LIVE"]}):eo?null:(0,n.jsxs)("div",{className:"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1 rounded-full bg-zinc-700/90 px-2 py-0.5 text-[9px] font-bold text-zinc-200",children:[(0,n.jsx)(F.Z,{className:"h-3 w-3"}),s("单帧","Still")]})]}):(0,n.jsx)("p",{className:"py-16 text-center text-sm text-zinc-600",children:s("请选择或连接设备","Pick or connect a device")}),eh?(0,n.jsx)("p",{className:"mt-3 text-center text-xs text-rose-300",children:eh}):null,k&&!eo?(0,n.jsx)("p",{className:"mt-3 text-center text-xs text-rose-300",children:k}):null,(0,n.jsx)("p",{className:"mt-3 text-center text-[10px] text-zinc-600",children:s("左键单击 / 双击 \xb7 右键长按 \xb7 坐标对齐 PNG 像素","Left tap/double \xb7 right long-press \xb7 PNG pixel coords")})]})]}),(0,n.jsxs)("div",{className:"space-y-4 xl:col-span-4",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.07] bg-black/40 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:s("遥测","Telemetry")}),u?(0,n.jsxs)("dl",{className:"mt-3 space-y-2 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"device"}),(0,n.jsxs)("dd",{className:"text-right text-zinc-200",children:[u.brand," ",u.model]})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"Android"}),(0,n.jsxs)("dd",{className:"text-zinc-300",children:[u.android_version," (API ",u.sdk,")"]})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"wm size"}),(0,n.jsx)("dd",{className:"text-cyan-300/90",children:S?"".concat(S.width,"\xd7").concat(S.height):u.resolution||"—"})]}),(0,n.jsx)("div",{className:"whitespace-pre-wrap text-[10px] leading-snug text-zinc-500",children:u.battery})]}):(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-600",children:s("在上方点「刷新设备信息」","Use Refresh device info above")})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/20 bg-gradient-to-b from-violet-500/[0.08] to-black/40 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-violet-300/80",children:s("导航坞","Nav dock")}),(0,n.jsx)("div",{className:"mt-3 grid grid-cols-3 gap-2",children:[["3","Home"],["4","Back"],["187","Recents"]].map(e=>{let[t,s]=e;return(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("key",{keycode:t}),eT()},className:"rounded-xl border border-white/10 bg-white/[0.06] py-3 text-xs font-semibold text-zinc-200 hover:bg-white/[0.1]",children:s},t)})}),(0,n.jsxs)("div",{className:"mt-2 grid grid-cols-2 gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("key",{keycode:"24"}),eT()},className:"rounded-xl border border-white/10 bg-black/30 py-2 text-[11px] text-zinc-300",children:"Vol+"}),(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("key",{keycode:"25"}),eT()},className:"rounded-xl border border-white/10 bg-black/30 py-2 text-[11px] text-zinc-300",children:"Vol−"})]})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-cyan-500/15 bg-cyan-500/[0.05] p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-cyan-300/80",children:s("手势","Gestures")}),(0,n.jsx)("div",{className:"mt-2 grid grid-cols-2 gap-2",children:["up","down","left","right"].map(e=>(0,n.jsx)("button",{type:"button",disabled:x||!r,onClick:()=>{h("swipe",{direction:e}),eT()},className:"rounded-lg border border-white/10 bg-black/30 py-2 font-mono text-[10px] uppercase text-zinc-300",children:e},e))})]})]})]})]})]})]})}let el=[{label:"getprop",cmd:"getprop ro.build.version.release"},{label:"top pkg",cmd:"dumpsys activity activities | grep -E 'mResumedActivity' | tail -n 1"},{label:"usb",cmd:"dumpsys usb | head -n 60"},{label:"surface",cmd:"dumpsys SurfaceFlinger | head -n 40"}];function ei(e,t,s){return e?(0,n.jsx)("span",{className:"rounded bg-emerald-500/15 px-2 py-0.5 text-[10px] text-emerald-200",children:t}):(0,n.jsx)("span",{className:"rounded bg-zinc-500/15 px-2 py-0.5 text-[10px] text-zinc-400",children:s})}function er(e){var t,s,l,i,r,a,o,c,d,x,u,m,h,p,b;let{t:g,notify:f,fetchJson:y,apiBase:w,busy:N,androidSerial:j,setAndroidSerial:k,devices:z,adbAvailable:S,apkPath:C,setApkPath:R,onAndroidAction:P,onCopy:I,onRefreshDevices:D}=e,[A,Z]=(0,_.useState)(null),[O,H]=(0,_.useState)(null),[B,K]=(0,_.useState)(null),[F,W]=(0,_.useState)(null),[Y,J]=(0,_.useState)(""),[G,V]=(0,_.useState)([]),[q,X]=(0,_.useState)("getprop ro.product.model"),[$,Q]=(0,_.useState)(""),[ee,et]=(0,_.useState)("300"),[es,er]=(0,_.useState)(""),[ea,eo]=(0,_.useState)(null),[ec,ed]=(0,_.useState)([]),[ex,eu]=(0,_.useState)(null),[em,eh]=(0,_.useState)("https://"),[ep,eb]=(0,_.useState)(""),[eg,ef]=(0,_.useState)(!1),[ev,ey]=(0,_.useState)(null),ew=!!(N||ev),eN=z.find(e=>e.serial===j)||null,ej=(0,_.useCallback)(async()=>{if(!j||!S){Z(null),H(null);return}ey("overview"),H(null);try{let e=await y("/android/overview?serial=".concat(encodeURIComponent(j)));Z(e)}catch(e){Z(null),H(e.message)}finally{ey(null)}},[S,j,y]),ek=(0,_.useCallback)(async()=>{W(null);try{let e=await y("/redroid/summary");K(e)}catch(e){K(null),W(e.message)}},[y]);(0,_.useEffect)(()=>{ej()},[ej]),(0,_.useEffect)(()=>{ek()},[ek]);let ez=async()=>{if(!j){f(g("请选择设备","Pick a device"));return}ey("packages");try{let e=encodeURIComponent(Y.trim()),t=await y("/android/packages?serial=".concat(encodeURIComponent(j),"&query=").concat(e,"&limit=80"));V(t.packages||[])}catch(e){f(e.message),V([])}finally{ey(null)}},eS=async()=>{if(!j){f(g("请选择设备","Pick a device"));return}let e=q.trim();if(e){ey("shell");try{var t,s;let n=await y("/android/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"shell",serial:j,payload:{command:e}})});Q(null!==(s=null!==(t=n.output)&&void 0!==t?t:n.message)&&void 0!==s?s:"")}catch(e){Q(e.message)}finally{ey(null)}}},e_=(0,_.useCallback)(async e=>{if(!j)return;let t=Math.min(3e3,Math.max(1,parseInt(ee,10)||200)),s=!!(null==e?void 0:e.silent);s||ey("logcat"),eo(null);try{var n;let e=await y("/android/logcat?serial=".concat(encodeURIComponent(j),"&lines=").concat(t));er(null!==(n=e.text)&&void 0!==n?n:"")}catch(e){er(""),eo(e.message)}finally{s||ey(null)}},[j,y,ee]);(0,_.useEffect)(()=>{if(!eg||!j||!S)return;let e=window.setInterval(()=>void e_({silent:!0}),3e3);return e_({silent:!0}),()=>clearInterval(e)},[S,j,eg,e_]);let eC=async()=>{if(!j){f(g("请选择设备","Pick a device"));return}ey("ui"),eu(null);try{let e=await y("/android/ui?serial=".concat(encodeURIComponent(j),"&limit=100"));ed(e.nodes||[])}catch(e){ed([]),eu(e.message)}finally{ey(null)}},eR=async(e,t)=>{ey("redroid:".concat(e));try{let s=await y("/redroid/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,name:t||""})});s.summary&&K(s.summary),f(s.message||"OK"),await ek(),D()}catch(e){f(e.message)}finally{ey(null)}},eP=async e=>{await P("key",{keycode:e})},eL=async()=>{let e=ep.trim();if(!e){f(g("请输入文字","Enter text"));return}await P("text",{text:e})},eM=async()=>{let e=em.trim();if(!e||"https://"===e){f(g("请输入 URL","Enter URL"));return}await P("open_url",{url:e})};return(0,n.jsxs)("div",{className:"mx-auto max-w-6xl space-y-6",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:g("安卓设备工作台","Android workstation")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:g("USB 真机与 Redroid 共用一套控制面,优先保证 USB 真机稳定。","USB phone and Redroid share one control surface.")})]}),S?(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ew||!j,onClick:()=>void ej(),className:"rounded-lg border border-white/10 bg-white/[0.05] px-3 py-1.5 text-xs text-zinc-300",children:g("刷新设备","Refresh device")}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>{ek(),D()},className:"rounded-lg border border-white/10 bg-white/[0.05] px-3 py-1.5 text-xs text-zinc-300",children:g("刷新 Redroid","Refresh Redroid")})]}):(0,n.jsx)("span",{className:"text-xs text-amber-200/90",children:g("宿主机未检测到 adb","adb not found on host")})]}),(0,n.jsx)("div",{className:"mt-4 flex flex-wrap gap-2",children:z.map(e=>(0,n.jsxs)("button",{type:"button",onClick:()=>k(e.serial),className:"rounded-xl border px-4 py-2 text-left text-xs ".concat(j===e.serial?"border-violet-500/50 bg-violet-500/10 text-white":"border-white/10 bg-black/30 text-zinc-400"),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("span",{className:"font-medium text-zinc-200",children:e.model||e.serial}),e.transport?(0,n.jsx)("span",{className:"rounded bg-white/10 px-1.5 py-0.5 font-mono text-[9px] uppercase text-zinc-500",children:e.transport}):null,e.kind?(0,n.jsx)("span",{className:"rounded bg-cyan-500/10 px-1.5 py-0.5 font-mono text-[9px] uppercase text-cyan-200",children:e.kind}):null]}),(0,n.jsx)("div",{className:"text-[10px] text-zinc-600",children:e.serial}),"device"!==(e.state||"").toLowerCase()?(0,n.jsx)("div",{className:"mt-1 text-[10px] font-medium text-amber-200/90",children:"unauthorized"===e.state?g("未授权,请在手机上允许 USB 调试。","Unauthorized, allow USB debugging on device."):"".concat(g("状态","State"),": ").concat(e.state)}):null]},e.serial))}),S&&0===z.length?(0,n.jsx)("p",{className:"mt-4 rounded-lg border border-amber-500/20 bg-amber-500/5 p-3 text-xs leading-relaxed text-amber-200/90",children:g("当前没有已授权设备。USB 真机请检查调试授权;Redroid 请先启动实例,再 adb connect 127.0.0.1:5555。","No authorized devices. For USB phones, confirm USB debugging. For Redroid, start an instance then adb connect 127.0.0.1:5555.")}):null]}),(0,n.jsxs)("div",{className:"grid gap-4 xl:grid-cols-[1.1fr_0.9fr]",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/15 bg-zinc-950/50 p-5",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-violet-300/90",children:g("真机诊断","Phone diagnostics")}),O?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:O}):null,A?(0,n.jsxs)("div",{className:"mt-3 space-y-3",children:[(0,n.jsxs)("dl",{className:"space-y-1.5 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"model"})," ",(0,n.jsxs)("dd",{className:"inline text-zinc-300",children:[A.brand," ",A.model]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"android"})," ",(0,n.jsxs)("dd",{className:"inline text-zinc-300",children:[A.android_version," (sdk ",A.sdk,")"]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"kind"})," ",(0,n.jsxs)("dd",{className:"inline text-zinc-300",children:[A.kind||(null==eN?void 0:eN.kind)||"unknown"," / ",A.transport||(null==eN?void 0:eN.transport)||"unknown"]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"display"})," ",(0,n.jsx)("dd",{className:"inline text-zinc-300",children:A.resolution})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"inline text-zinc-600",children:"rotation"})," ",(0,n.jsx)("dd",{className:"inline text-zinc-300",children:A.rotation})]}),(0,n.jsx)("div",{className:"whitespace-pre-wrap text-[10px] leading-snug text-zinc-500",children:A.battery}),(0,n.jsx)("div",{className:"line-clamp-3 text-[10px] text-zinc-500",children:A.focus})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[ei(null===(t=A.diagnostics)||void 0===t?void 0:t.ready,g("已启动","Boot ready"),g("未完成启动","Boot pending")),ei(null===(s=A.diagnostics)||void 0===s?void 0:s.google_play,"Google Play","No Play"),ei(null===(l=A.diagnostics)||void 0===l?void 0:l.google_services,"GMS","No GMS"),ei(null===(i=A.diagnostics)||void 0===i?void 0:i.magisk,"Magisk","No Magisk"),ei(null===(r=A.diagnostics)||void 0===r?void 0:r.root,"Root","No root")]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/5 bg-black/20 p-3 text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{children:["boot_completed: ",(null===(a=A.diagnostics)||void 0===a?void 0:a.boot_completed)||"-"]}),(0,n.jsxs)("div",{children:["provisioned: ",(null===(o=A.diagnostics)||void 0===o?void 0:o.device_provisioned)||"-"]}),(0,n.jsxs)("div",{children:["setup_complete: ",(null===(c=A.diagnostics)||void 0===c?void 0:c.user_setup_complete)||"-"]}),(0,n.jsxs)("div",{children:["abi: ",(null===(d=A.diagnostics)||void 0===d?void 0:d.abi)||"-"]}),(0,n.jsxs)("div",{className:"truncate",children:["hardware: ",(null===(x=A.diagnostics)||void 0===x?void 0:x.hardware)||"-"]})]})]}):O?null:(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:g("加载中","Loading")})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-cyan-500/15 bg-zinc-950/50 p-5",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-cyan-300/90",children:g("Redroid 板块","Redroid panel")}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("start"),className:"rounded-lg bg-emerald-500/20 px-3 py-1.5 text-xs text-emerald-100 ring-1 ring-emerald-500/30",children:g("启动默认实例","Start default")})]}),F?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:F}):null,B?(0,n.jsxs)("div",{className:"mt-3 space-y-3 text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/5 bg-black/20 p-3",children:[(0,n.jsxs)("div",{children:["arch: ",B.arch||"-"]}),(0,n.jsxs)("div",{className:"truncate",children:["image: ",B.image||"-"]}),(0,n.jsxs)("div",{children:["profile: ",B.device_profile||"-"]}),(0,n.jsxs)("div",{children:["gpu: ",B.gpu_mode||"-"]}),(0,n.jsxs)("div",{children:["adb: 127.0.0.1:",B.default_port||5555]})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[ei(null===(u=B.requirements)||void 0===u?void 0:u.docker_available,"Docker","No Docker"),ei(null===(m=B.requirements)||void 0===m?void 0:m.adb_available,"ADB","No ADB"),ei(null===(h=B.requirements)||void 0===h?void 0:h.kvm,"KVM","No KVM"),ei(null===(p=B.requirements)||void 0===p?void 0:p.binderfs,"binderfs","No binderfs")]}),(0,n.jsxs)("div",{className:"space-y-2",children:[(B.instances||[]).map(e=>{var t,s,l,i;return(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/25 p-3",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"font-medium text-zinc-100",children:e.name}),(0,n.jsxs)("div",{className:"font-mono text-[10px] text-zinc-500",children:[e.port?"127.0.0.1:".concat(e.port):"-"," / ",e.status_text||"-"]})]}),(0,n.jsxs)("div",{className:"flex gap-1",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("start",e.name),className:"rounded bg-emerald-500/15 px-2 py-1 text-[10px] text-emerald-200",children:"Start"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("restart",e.name),className:"rounded bg-amber-500/15 px-2 py-1 text-[10px] text-amber-200",children:"Restart"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("adb_connect",e.name),className:"rounded bg-cyan-500/15 px-2 py-1 text-[10px] text-cyan-200",children:"ADB"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eR("stop",e.name),className:"rounded bg-rose-500/15 px-2 py-1 text-[10px] text-rose-200",children:"Stop"})]})]}),(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap gap-2",children:[ei(null===(t=e.diagnostics)||void 0===t?void 0:t.ready,g("系统就绪","System ready"),g("启动中","Booting")),ei(null===(s=e.diagnostics)||void 0===s?void 0:s.google_play,"Play","No Play"),ei(null===(l=e.diagnostics)||void 0===l?void 0:l.magisk,"Magisk","No Magisk"),ei(null===(i=e.diagnostics)||void 0===i?void 0:i.root,"Root","No root")]}),e.data_dir?(0,n.jsx)("div",{className:"mt-2 truncate font-mono text-[10px] text-zinc-500",children:e.data_dir}):null]},e.name)}),(null===(b=B.instances)||void 0===b?void 0:b.length)?null:(0,n.jsx)("p",{className:"rounded-xl border border-white/5 bg-black/20 p-3 text-xs text-zinc-500",children:g("当前没有 Redroid 实例。默认动作会创建 redroid13-1。","No Redroid instances yet. Default actions create redroid13-1.")})]})]}):(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:g("读取 Redroid 状态中","Loading Redroid status")})]})]}),(0,n.jsx)(en,{t:g,apiBase:w,fetchJson:y,serial:j,devices:z,setSerial:k,adbAvailable:S,lock:ew,overview:A,onAndroidAction:P,notify:f,onRefreshDevices:D}),S&&j?(0,n.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-5",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-emerald-300/90",children:g("快捷控制","Quick controls")}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("3"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Home"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("4"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Back"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("187"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Recents"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("wake"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Wake"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("launch_package",{package:"com.zhiliaoapp.musically"}),className:"rounded-lg bg-gradient-to-r from-pink-500/25 to-violet-500/25 px-3 py-1.5 text-xs ring-1 ring-white/10",children:"TikTok"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("24"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Vol+"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("25"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Vol-"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eP("66"),className:"rounded-lg border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs",children:"Enter"})]}),(0,n.jsx)("p",{className:"mt-3 text-[10px] text-zinc-600",children:g("滑动手势","Swipe gestures")}),(0,n.jsx)("div",{className:"mt-1 flex flex-wrap gap-2",children:["up","down","left","right"].map(e=>(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("swipe",{direction:e}),className:"rounded-lg border border-white/10 bg-black/30 px-2.5 py-1 font-mono text-[10px] uppercase text-zinc-300",children:e},e))}),(0,n.jsxs)("div",{className:"mt-4 rounded-lg border border-white/5 bg-black/20 p-3",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:g("ADB 文本输入","ADB text input")}),(0,n.jsxs)("div",{className:"mt-2 flex flex-col gap-2 sm:flex-row",children:[(0,n.jsx)("input",{className:"min-w-0 flex-1 rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-xs",value:ep,onChange:e=>eb(e.target.value),placeholder:"hello / 123",onKeyDown:e=>{"Enter"===e.key&&eL()}}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eL(),className:"rounded-lg bg-emerald-500/20 px-3 py-2 text-xs text-emerald-100 ring-1 ring-emerald-500/30",children:g("发送","Send")})]})]}),(0,n.jsxs)("div",{className:"mt-4 flex flex-col gap-2 sm:flex-row sm:items-center",children:[(0,n.jsx)("input",{className:"min-w-0 flex-1 rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-xs",value:em,onChange:e=>eh(e.target.value),placeholder:"https://"}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eM(),className:"rounded-lg bg-violet-500/20 px-3 py-2 text-xs text-violet-100 ring-1 ring-violet-500/30",children:g("打开链接","Open URL")})]})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-5",children:[(0,n.jsxs)("h4",{className:"flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-cyan-300/90",children:[(0,n.jsx)(L.Z,{className:"h-4 w-4"}),g("USB 真机优化建议","USB optimization")]}),(0,n.jsxs)("ul",{className:"mt-3 space-y-2 text-xs leading-relaxed text-zinc-400",children:[(0,n.jsx)("li",{children:g("优先使用主板直连 USB,不要经过不稳的 HUB。","Prefer direct motherboard USB, not unstable hubs.")}),(0,n.jsx)("li",{children:g("开发板端固定 adb server,避免频繁 kill-server。","Keep adb server stable and avoid frequent kill-server.")}),(0,n.jsx)("li",{children:g("镜像页默认支持 scrcpy H.264 真流,截图模式作为回退。","Use scrcpy H.264 live stream first, screenshot mode as fallback.")}),(0,n.jsx)("li",{children:g("如果 TikTok / YouTube App 直播,要先确认屏幕常亮、分辨率稳定、USB 供电足够。","For TikTok / YouTube app live, keep screen on, resolution stable, and USB power sufficient.")})]})]})]}):null,S&&j?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(M.Z,{className:"h-4 w-4 text-emerald-400"}),g("包名搜索与启动","Packages")]}),(0,n.jsxs)("div",{className:"mt-3 flex flex-col gap-2 sm:flex-row",children:[(0,n.jsx)("input",{className:"min-w-0 flex-1 rounded-xl border border-white/10 bg-black/40 px-4 py-2 text-sm",value:Y,onChange:e=>J(e.target.value),placeholder:"tiktok / musically / youtube",onKeyDown:e=>{"Enter"===e.key&&ez()}}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void ez(),className:"rounded-xl bg-emerald-500/20 px-4 py-2 text-sm text-emerald-100 ring-1 ring-emerald-500/30",children:g("搜索","Search")})]}),(0,n.jsxs)("ul",{className:"mt-4 max-h-48 space-y-1 overflow-y-auto rounded-lg border border-white/5 bg-black/30 p-2 font-mono text-[11px]",children:[G.map(e=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center justify-between gap-2 py-1 text-zinc-400",children:[(0,n.jsx)("span",{className:"min-w-0 truncate text-zinc-300",children:e.package}),(0,n.jsxs)("span",{className:"flex shrink-0 gap-1",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("launch_package",{package:e.package}),className:"rounded bg-white/10 px-2 py-0.5 text-[10px] text-zinc-200",children:g("启动","Launch")}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("force_stop",{package:e.package}),className:"rounded bg-rose-500/15 px-2 py-0.5 text-[10px] text-rose-200",children:g("停止","Stop")})]})]},e.package)),G.length?null:(0,n.jsx)("li",{className:"py-2 text-center text-zinc-600",children:g("暂无结果","No results")})]})]}):null,S&&j?(0,n.jsxs)("div",{className:"grid gap-6 xl:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(T.Z,{className:"h-4 w-4 text-amber-400"}),"ADB shell"]}),(0,n.jsx)("div",{className:"mt-2 flex flex-wrap gap-1.5",children:el.map(e=>(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>X(e.cmd),className:"rounded-md border border-white/10 bg-white/[0.04] px-2 py-1 text-[10px] text-zinc-400 hover:text-zinc-200",children:e.label},e.label))}),(0,n.jsx)("textarea",{className:"mt-3 min-h-[100px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-3 font-mono text-xs text-zinc-200",value:q,onChange:e=>X(e.target.value),spellCheck:!1,onKeyDown:e=>{"Enter"===e.key&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),eS())}}),(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eS(),className:"rounded-xl bg-amber-500/20 px-4 py-2 text-sm text-amber-100 ring-1 ring-amber-500/30",children:"shell"===ev?(0,n.jsxs)("span",{className:"inline-flex items-center gap-2",children:[(0,n.jsx)(v.Z,{className:"h-3.5 w-3.5 animate-spin"}),"Run"]}):"Run"}),$?(0,n.jsxs)("button",{type:"button",disabled:!$,onClick:()=>I($),className:"inline-flex items-center gap-1 rounded-lg border border-white/10 px-3 py-1.5 text-xs text-zinc-400 hover:text-zinc-200",children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),g("复制输出","Copy")]}):null]}),$?(0,n.jsx)("pre",{className:"mt-3 max-h-64 overflow-auto whitespace-pre-wrap rounded-lg border border-white/5 bg-black/40 p-3 font-mono text-[11px] text-zinc-400 xl:max-h-[min(24rem,50vh)]",children:$}):null]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:g("Logcat","Logcat")}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap items-center gap-2",children:[(0,n.jsx)("input",{className:"w-24 rounded-lg border border-white/10 bg-black/40 px-3 py-2 font-mono text-xs",value:ee,onChange:e=>et(e.target.value)}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2 text-[11px] text-zinc-400",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:eg,onChange:e=>ef(e.target.checked)}),g("每 3 秒自动刷新","Auto every 3s")]}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void e_(),className:"rounded-xl bg-cyan-500/20 px-4 py-2 text-sm text-cyan-100 ring-1 ring-cyan-500/30",children:g("拉取日志","Pull logs")}),es?(0,n.jsxs)("button",{type:"button",onClick:()=>I(es),className:"inline-flex items-center gap-1 rounded-lg border border-white/10 px-3 py-1.5 text-xs text-zinc-400 hover:text-zinc-200",children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),g("复制","Copy")]}):null]}),ea?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:ea}):null,es?(0,n.jsx)("pre",{className:"mt-3 max-h-72 overflow-auto whitespace-pre-wrap rounded-lg border border-white/5 bg-black/50 p-3 font-mono text-[10px] leading-tight text-zinc-500 xl:max-h-[min(24rem,50vh)]",children:es}):null]})]}):null,S&&j?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(E.Z,{className:"h-4 w-4 text-fuchsia-400"}),g("界面节点","UI nodes")]}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void eC(),className:"mt-3 rounded-xl border border-fuchsia-500/30 bg-fuchsia-500/10 px-4 py-2 text-sm text-fuchsia-100",children:g("刷新节点","Refresh nodes")}),ex?(0,n.jsx)("p",{className:"mt-2 text-xs text-rose-300",children:ex}):null,(0,n.jsxs)("ul",{className:"mt-3 max-h-64 space-y-1 overflow-y-auto rounded-lg border border-white/5 bg-black/30 p-2 text-[11px]",children:[ec.map((e,t)=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center justify-between gap-2 border-b border-white/[0.04] py-1.5 text-zinc-400 last:border-0",children:[(0,n.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,n.jsx)("span",{className:"text-zinc-200",children:e.label}),e.resource_id?(0,n.jsx)("span",{className:"ml-2 font-mono text-[10px] text-zinc-600",children:e.resource_id}):null,(0,n.jsxs)("div",{className:"font-mono text-[10px] text-zinc-600",children:["(",e.center_x,", ",e.center_y,")",e.clickable?" click":""]})]}),(0,n.jsx)("button",{type:"button",disabled:ew,onClick:()=>void P("tap",{x:e.center_x,y:e.center_y}),className:"shrink-0 rounded bg-white/10 px-2 py-1 text-[10px] text-zinc-200",children:"Tap"})]},"".concat(e.center_x,"-").concat(e.center_y,"-").concat(t))),ec.length||ex?null:(0,n.jsx)("li",{className:"py-4 text-center text-zinc-600",children:g("尚未加载","Not loaded")})]})]}):null,S&&j?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:g("安装 APK","Install APK")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:g("先 adb push 到 /sdcard/ 再执行安装。","Push the APK to /sdcard/ first.")}),(0,n.jsx)("input",{className:"mt-4 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm",value:C,onChange:e=>R(e.target.value)}),(0,n.jsx)("button",{type:"button",disabled:ew||!S||!j,onClick:()=>void P("install_apk",{path:C}),className:"mt-3 rounded-xl bg-emerald-500/20 px-4 py-2 text-sm font-medium text-emerald-100 ring-1 ring-emerald-500/30",children:"pm install"})]}):null]})}var ea=s(9897),eo=s(4554),ec=s(7689),ed=s(8930),ex=s(8401);function eu(e){let{t,title:s,subtitle:l,steps:i,onNavigate:r}=e;return(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/25 bg-gradient-to-br from-violet-500/10 via-zinc-950/40 to-fuchsia-500/5 p-6 shadow-lg shadow-violet-900/10",children:[(0,n.jsx)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:s}),(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-400",children:l}),(0,n.jsx)("div",{className:"mt-6 flex flex-col items-center gap-4 sm:flex-row sm:flex-wrap sm:justify-center",children:i.map((e,t)=>(0,n.jsxs)("div",{className:"flex items-center gap-4",children:[e.openUrl||e.target&&r?(0,n.jsxs)("button",{type:"button",onClick:()=>{if(e.openUrl){window.open((0,ex.p)(e.openUrl),"_blank","noopener,noreferrer");return}e.target&&r&&r(e.target)},className:"flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ring-2 ring-white/10 transition hover:ring-violet-400/50 hover:brightness-110 ".concat(e.gradient),children:[(0,n.jsx)("span",{children:e.label}),e.sub?(0,n.jsx)("span",{className:"mt-1 text-[10px] font-normal text-white/80",children:e.sub}):null]}):(0,n.jsxs)("div",{className:"flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ".concat(e.gradient),children:[(0,n.jsx)("span",{children:e.label}),e.sub?(0,n.jsx)("span",{className:"mt-1 text-[10px] font-normal text-white/80",children:e.sub}):null]}),t8?e.slice(-8):e;if(e.includes("live2/")){let t=e.split("/"),s=t[t.length-1]||"";return s.length>8?s.slice(-8):s}}}let t=e.trim();return!t||t.includes("\n")||t.toLowerCase().startsWith("rtmp")?"":t.length>8?t.slice(-8):t}function eh(e){let t=[];for(let s of e.split(/\r?\n/)){let e=s.trim();if(!e||e.startsWith("#")||!/douyin\.com|v\.douyin\.com/i.test(e))continue;let n=e.match(/(https?:\/\/live\.douyin\.com\/[a-zA-Z0-9_-]+)/i);if(n){t.push(n[1].replace(/^http:\/\//i,"https://"));continue}let l=e.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);if(l){t.push("https://live.douyin.com/".concat(l[1]));continue}let i=e.match(/(\d{8,})/);i&&t.push("https://live.douyin.com/".concat(i[1]))}return Array.from(new Set(t)).slice(0,16)}function ep(e){let t="",s=!0,n="",l=!1,i=e.split(/\r?\n/),r=!1;for(let e of i){let i=e.trim();if(/^\[youtube\]/i.test(i)){r=!0;continue}if(/^\[/.test(i)){r=!1;continue}if(!r||!i||i.startsWith("#")||i.startsWith(";"))continue;let a=i.indexOf("=");if(a<0)continue;let o=i.slice(0,a).trim().toLowerCase(),c=i.slice(a+1).trim().split(/[#;]/)[0].trim();"key"===o||"stream_key"===o?t=c:"rtmps"===o?s=!/^(0|false|否)/i.test(c):"bitrate"===o?n=c:"fast_audio"===o&&(l=/^(1|true|yes|是|开|on)/i.test(c))}return{key:t,rtmps:s,bitrate:n,fastAudio:l}}function eb(e){return"URL_config.".concat(e.replace(/[^a-zA-Z0-9_.-]/g,"_"),".ini")}function eg(e){let t=e.bitrate.trim()?"bitrate = ".concat(e.bitrate.trim()):"# bitrate = 4000";return"[youtube]\n# YouTube 推流 key(工作室 → 直播 → 串流密钥)\nkey = ".concat(e.key.trim(),"\n\n# 使用 RTMPS;填 否 则 RTMP\nrtmps = ").concat(e.rtmps?"是":"否","\n\n# 视频比特率 kbps(可选)\n").concat(t,"\n\n# 轻量音频链,减轻 CPU:1 / 是\nfast_audio = ").concat(e.fastAudio?"1":"0","\n")}function ef(e){if(e<60)return"".concat(e,"s");let t=Math.floor(e/60);return t<60?"".concat(t,"m ").concat(e%60,"s"):"".concat(Math.floor(t/60),"h ").concat(t%60,"m")}function ev(e){var t,s,l;let{t:i,currentProc:r,fetchJson:a,urlListText:o,keySuffixUi:c,showKeyRow:d=!0,pollMs:x=1e3,refreshToken:u=0}=e,[m,h]=(0,_.useState)(""),[p,b]=(0,_.useState)(""),[g,f]=(0,_.useState)(""),[v,w]=(0,_.useState)(""),[N,j]=(0,_.useState)(""),[k,z]=(0,_.useState)([]),[S,C]=(0,_.useState)(null),[R,P]=(0,_.useState)(!1),[L,M]=(0,_.useState)(null),[T,U]=(0,_.useState)(0),[E,I]=(0,_.useState)(!0),D=(0,_.useRef)(null),A=(0,_.useRef)(null),O=(0,_.useRef)(!1),H=(0,_.useRef)(!1),B=(0,_.useRef)(!1),W=(0,_.useRef)(r),Y=(0,_.useRef)(0),J=function(e){let t=[];for(let s of e.split(/\r?\n/)){let e=s.trim();if(!e||e.startsWith("#")||!/douyin\.com|v\.douyin\.com/i.test(e))continue;let n=e.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);if(n){t.push(n[1]);continue}let l=e.match(/(\d{8,})/);t.push(l?l[1]:e.slice(0,96))}return Array.from(new Set(t)).slice(0,12)}(o),G=/^(online|running)$/i.test(m),V=function(e){if(!e)return null;let t=null;for(let s of e.split(/\r?\n/)){let e=s.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);e&&(t=e[1]);let n=s.match(/https?:\/\/[^/\s]*douyin\.com\/(\d{8,})/i);n&&(t=n[1])}return t}(p),q=null!==(s=eh(o)[0])&&void 0!==s?s:"",X=V||(null!==(l=null===(t=q.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i))||void 0===t?void 0:t[1])&&void 0!==l?l:null),$=X?"https://live.douyin.com/".concat(X):q||null,Q=(0,_.useCallback)(async()=>{let e=W.current.trim();if(!e)return;if(H.current){B.current=!0;return}H.current=!0;let t=++Y.current;try{let s=await a("/status?process=".concat(encodeURIComponent(e)));if(t!==Y.current||e!==W.current.trim())return;let n=s.process_status||"unknown";h(n),b(s.recent_log||""),f(s.recent_error||""),w(s.business_status||""),j(s.business_note||""),z(Array.isArray(s.ffmpeg_pids)?s.ffmpeg_pids:[]),C("number"==typeof s.log_age_seconds?s.log_age_seconds:null);let l=/^(online|running)$/i.test(n);l&&!O.current&&M(Date.now()),l||M(null),O.current=l}catch(s){if(t!==Y.current||e!==W.current.trim())return;h("error"),w("error"),j(""),z([]),C(null)}finally{H.current=!1,B.current&&(B.current=!1,window.setTimeout(()=>void Q(),0))}},[a]);(0,_.useEffect)(()=>{if(W.current=r,Y.current+=1,B.current=!1,!r){h(""),b(""),f(""),w(""),j(""),z([]),C(null),M(null),O.current=!1;return}h(""),b(""),f(""),w(""),j(""),z([]),C(null),M(null),O.current=!1,Q()},[r,Q]),(0,_.useEffect)(()=>{let e=()=>I("visible"===document.visibilityState);return e(),document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[]),(0,_.useEffect)(()=>{r&&Q()},[r,Q,u]),(0,_.useEffect)(()=>{if(R||!E||!r)return;let e=window.setInterval(()=>void Q(),x);return()=>clearInterval(e)},[R,E,r,Q,x]),(0,_.useEffect)(()=>{let e=()=>{"visible"===document.visibilityState&&Q()};return document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[Q]),(0,_.useEffect)(()=>{if(!L)return;let e=window.setInterval(()=>U(e=>e+1),1e3);return()=>clearInterval(e)},[L]),(0,_.useEffect)(()=>{if(R||!E)return;let e=D.current;e&&(e.scrollTop=e.scrollHeight)},[p,R,E]),(0,_.useEffect)(()=>{if(R||!E)return;let e=A.current;e&&(e.scrollTop=e.scrollHeight)},[g,R,E]);let ee=null==L?i("—(未检测到在线)","— (not online)"):ef(Math.max(0,Math.floor((Date.now()-L)/1e3))),et=R?i("已暂停刷新","Paused"):E?i("每秒刷新","~1s refresh"):i("后台暂停","Hidden"),es=R?"bg-amber-500/20 text-amber-100 ring-amber-500/35":E?"bg-emerald-500/15 text-emerald-200/90 ring-emerald-500/25":"bg-sky-500/15 text-sky-100 ring-sky-500/25";return(0,n.jsxs)("section",{className:"rounded-2xl border border-emerald-500/20 bg-gradient-to-b from-emerald-500/[0.07] to-zinc-950/80 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsx)("span",{className:"sr-only","aria-hidden":!0,children:T}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:i("当前直播日志","Live process log")}),(0,n.jsx)("span",{className:"rounded-full bg-white/10 px-2 py-0.5 font-mono text-[10px] text-zinc-300 ring-1 ring-white/10",children:r||"—"}),(0,n.jsx)("span",{className:"rounded-full px-2 py-0.5 text-[10px] font-medium ring-1 ".concat(es),children:et})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsxs)("button",{type:"button",onClick:()=>void Q(),className:"inline-flex items-center gap-1 rounded-lg border border-white/10 bg-white/[0.05] px-3 py-1.5 text-xs text-zinc-300 hover:bg-white/[0.08]",children:[(0,n.jsx)(y.Z,{className:"h-3.5 w-3.5"}),i("立即拉取","Refresh")]}),(0,n.jsxs)("button",{type:"button",onClick:()=>P(e=>!e),className:"inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-xs ring-1 ".concat(R?"bg-amber-500/20 text-amber-100 ring-amber-500/35":"border border-white/10 bg-black/30 text-zinc-300"),children:[R?(0,n.jsx)(K.Z,{className:"h-3.5 w-3.5"}):(0,n.jsx)(F.Z,{className:"h-3.5 w-3.5"}),R?i("继续自动刷新","Resume"):i("暂停自动刷新","Pause")]})]})]}),(0,n.jsxs)("div",{className:"mt-4 space-y-3 rounded-xl border border-white/[0.06] bg-black/25 p-4",children:[(0,n.jsxs)("div",{className:"grid gap-2 text-xs sm:grid-cols-2",children:[(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("进程状态","Status")}),(0,n.jsx)("span",{className:"font-medium text-zinc-200",children:function(e,t){let s=(t||"unknown").toLowerCase();return"online"===s||"running"===s?e("运行中(PM2/进程在线)","Running (process online)"):"stopped"===s||"stopping"===s?e("已停止","Stopped"):"not_found"===s||"errored"===s?e("未运行或未找到","Not running / not found"):"invalid"===s?e("无效进程名","Invalid process"):t||"—"}(i,m)})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("Business state","Business state")}),(0,n.jsx)("span",{className:"font-medium text-cyan-200/90",children:function(e,t,s){let n=(t||"").toLowerCase();return"streaming"===n?e("Pushing to YouTube","Pushing to YouTube"):"waiting_source"===n?e("Waiting for the upstream live source","Waiting for the upstream live source"):"source_live"===n?e("Source live detected, but no active FFmpeg relay worker","Source live detected, but no active FFmpeg relay worker"):"monitoring"===n?e("Process online and monitoring the source","Process online and monitoring the source"):"misconfigured"===n?e("YouTube key missing or invalid","YouTube key missing or invalid"):"stale"===n?e("Process online but the log heartbeat is stale","Process online but the log heartbeat is stale"):"error"===n?e("Recent process error detected","Recent process error detected"):(null==s?void 0:s.trim())?s.trim():e("No business-state hint yet","No business-state hint yet")}(i,v,N)})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("本次在线时长(估算)","Online duration (est.)")}),(0,n.jsx)("span",{className:"font-mono text-cyan-200/90",children:ee})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("FFmpeg workers","FFmpeg workers")}),(0,n.jsxs)("span",{className:"font-mono text-zinc-300",children:[k.length?k.join(", "):"none",null!=S?" \xb7 log ".concat(ef(Math.max(0,Math.floor(S)))):""]})]})]}),d?(0,n.jsxs)("div",{className:"flex flex-wrap gap-2 text-xs",children:[(0,n.jsx)("span",{className:"text-zinc-500",children:i("YouTube key 尾码(参考)","YT key suffix")}),(0,n.jsx)("span",{className:"font-mono text-zinc-300",children:c||"—"})]}):null,$?(0,n.jsxs)("div",{className:"rounded-lg border border-violet-500/20 bg-violet-500/[0.06] px-3 py-2.5",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsx)("span",{className:"text-[11px] font-medium text-zinc-400",children:V?i("当前直播源站(日志)","Current source (from log)"):G?i("配置中的源站地址","Configured source URL"):i("源站快捷入口","Source quick link")}),(0,n.jsxs)("a",{href:$,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-lg bg-violet-500/20 px-3 py-1.5 text-xs font-medium text-violet-100 ring-1 ring-violet-500/35 transition hover:bg-violet-500/30",children:[(0,n.jsx)(Z.Z,{className:"h-3.5 w-3.5 shrink-0 opacity-90"}),X||i("打开抖音直播页","Open Douyin live")]})]}),J.length>1&&V?(0,n.jsxs)("p",{className:"mt-2 text-[10px] text-zinc-600",children:[i("配置中还有","Also in config:")," ",J.filter(e=>e!==X).slice(0,3).map(e=>(0,n.jsx)("a",{href:"https://live.douyin.com/".concat(e),target:"_blank",rel:"noreferrer",className:"ml-1 text-violet-400/90 underline-offset-2 hover:underline",children:e},e)),J.length>4?"…":null]}):null]}):(0,n.jsx)("p",{className:"text-[11px] text-zinc-600",children:i("(日志与地址列表中暂无抖音房间)","(No Douyin room in log or URL list)")})]}),"not_found"!==m&&"invalid"!==m?(0,n.jsxs)("div",{className:"mt-4 grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"text-[11px] font-semibold uppercase tracking-wider text-emerald-400/90",children:i("进程输出(stdout / 合并日志)","Process output")}),(0,n.jsx)("pre",{ref:D,className:"log-live-scroll mt-2 max-h-[min(22rem,42vh)] min-h-[12rem] overflow-auto whitespace-pre-wrap rounded-xl border border-emerald-500/20 bg-black/55 p-3 font-mono text-[10px] leading-relaxed text-emerald-100/95",children:p.trim()||i("(暂无)","(empty)")})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"text-[11px] font-semibold uppercase tracking-wider text-rose-400/90",children:i("异常信息(stderr)","Stderr")}),(0,n.jsx)("pre",{ref:A,className:"log-live-scroll mt-2 max-h-[min(22rem,42vh)] min-h-[12rem] overflow-auto whitespace-pre-wrap rounded-xl border border-rose-500/20 bg-black/55 p-3 font-mono text-[10px] leading-relaxed text-rose-100/95",children:g.trim()||i("(暂无)","(empty)")})]})]}):(0,n.jsx)("p",{className:"mt-4 text-xs text-zinc-500",children:i("进程未在 PM2 / 本地注册表中运行,日志区域已隐藏。","Process not running — log panes hidden.")})]})}function ey(e){return/tiktok/i.test(e.script)||/tiktok/i.test(e.pm2)}let ew=[{id:"720p60",labelZh:"720p @ 60Hz",labelEn:"720p @ 60Hz",spec:"1280x720, 59.94/60Hz, RGB/YUV 有限",hintZh:"板端 HDMI 输出时序与显示端一致;下游画布建议 1280\xd7720。",hintEn:"Match SoC HDMI timing to the display; downstream canvas e.g. 1280\xd7720."},{id:"1080p30",labelZh:"1080p @ 30Hz",labelEn:"1080p @ 30Hz",spec:"1920x1080, 30Hz",hintZh:"带宽紧张时可优先 1080p30;检查线材与接口规格。",hintEn:"Prefer 1080p30 when bandwidth is tight; check cable and port specs."},{id:"1080p60",labelZh:"1080p @ 60Hz",labelEn:"1080p @ 60Hz",spec:"1920x1080, 60Hz, 高刷转播",hintZh:"两端均需稳定支持 1080p60;长时间运行注意散热。",hintEn:"Both ends need stable 1080p60; mind thermals for long runs."}],eN="live-hub-tiktok-hdmi-check-v1",ej="live-hub-tiktok-hdmi-notes-v1",ek="live-hub-tiktok-source-mode-v1";function ez(e){var t;let{t:s,busy:l,entries:i,currentProc:r,setCurrentProc:a,urlConfig:o,setUrlConfig:c,onRunProcess:d,onSaveUrlConfig:x,onReplayGoLive:u,onCopy:m,fetchJson:h,apiPrefix:p,quickLinks:b,hdmiStatus:g,notify:f,onNavigate:v}=e,y=(0,_.useMemo)(()=>i.filter(ey),[i]),w=y.length?y:i,[N,j]=(0,_.useState)("srs"),[k,z]=(0,_.useState)([]),[S,C]=(0,_.useState)(!1),[R,P]=(0,_.useState)(!1),[L,M]=(0,_.useState)("1080p30"),[T,E]=(0,_.useState)("1080p30"),[I,A]=(0,_.useState)(!1),[Z,O]=(0,_.useState)(!0),[H,K]=(0,_.useState)(null),F=(0,_.useRef)(!1),W=(0,_.useRef)(o),[J,G]=(0,_.useState)(""),[V,q]=(0,_.useState)({}),X=(0,_.useCallback)(e=>{W.current=e,c(e)},[c]),$=(0,_.useCallback)(e=>{j(e);try{window.localStorage.setItem(ek,e)}catch(e){}},[]);(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(ek);("ffmpeg"===e||"replay"===e||"srs"===e)&&("ffmpeg"!==e&&"replay"!==e?j(e):j("srs"))}catch(e){}},[]),(0,_.useEffect)(()=>{F.current=!1},[r]),(0,_.useEffect)(()=>{W.current=o},[o]);let Q=(0,_.useCallback)(async()=>{if(r)try{var e;let t=new URLSearchParams({process:r,_ts:String(Date.now())}),s=await h("/get_url_config?".concat(t));X(null!==(e=s.content)&&void 0!==e?e:"")}catch(e){}},[X,r,h]);(0,_.useEffect)(()=>{if(!r||!Z||"ffmpeg"!==N)return;let e=window.setInterval(()=>{F.current||Q()},8e3);return()=>clearInterval(e)},[r,Z,Q,N]),(0,_.useEffect)(()=>{"ffmpeg"===N&&r&&Q()},[N,r,Q]);let ee=(0,_.useCallback)(async()=>{if(r){C(!0);try{var e;let t=await h("/tiktok_replay/list?process=".concat(encodeURIComponent(r)));z(null!==(e=t.files)&&void 0!==e?e:[])}catch(e){f(e.message),z([])}finally{C(!1)}}},[r,h,f]);(0,_.useEffect)(()=>{"replay"===N&&r&&ee()},[N,r,ee]),(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(eN);e&&q(JSON.parse(e))}catch(e){}try{G(window.localStorage.getItem(ej)||"")}catch(e){}},[]);let et=(0,_.useCallback)(e=>{q(e);try{window.localStorage.setItem(eN,JSON.stringify(e))}catch(e){}},[]),es=e=>{G(e);try{window.localStorage.setItem(ej,e)}catch(e){}},en=async()=>{if(r){A(!0),K(null),F.current=!1;try{var e;let t=new URLSearchParams({process:r,_ts:String(Date.now())}),n=await h("/get_url_config?".concat(t));X(null!==(e=n.content)&&void 0!==e?e:""),K(s("已从服务器读取 URL_config","Reloaded URL_config from server"))}catch(e){K(e.message)}finally{A(!1)}}},el=async()=>{try{await Promise.resolve(x(W.current)),F.current=!1}catch(e){}},ei=async e=>{if(r){P(!0);try{await h("/tiktok_replay/delete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({process:r,filename:e})}),f(s("已删除文件","File removed")),await ee()}catch(e){f(e.message)}finally{P(!1)}}},er=async e=>{var t;let n=null===(t=e.target.files)||void 0===t?void 0:t[0];if(e.target.value="",n&&r){P(!0);try{let e=new FormData;e.append("file",n);let t=await (0,Y.N)("".concat(p,"/tiktok_replay/upload?process=").concat(encodeURIComponent(r)),{method:"POST",body:e});f(t.message||s("上传成功","Uploaded")),await ee()}catch(e){f(e.message)}finally{P(!1)}}},ex=l||I||R,em=ew.find(e=>e.id===T),eh=!!(null==g?void 0:g.can_stream_hdmi),ep=(null==g?void 0:g.preferred_device)||(null==g?void 0:null===(t=g.video_devices)||void 0===t?void 0:t[0])||"";return(0,n.jsxs)("div",{className:"mx-auto max-w-4xl space-y-6",children:[v?(0,n.jsx)(eu,{t:s,title:s("TikTok HDMI 硬件链路","TikTok HDMI hardware chain"),subtitle:s("板端编码经 HDMI 到显示/下游设备;与「网络」页顶卡相同的箭头风格。","Encode on SoC → HDMI → display/downstream; same arrow style as Network header."),onNavigate:v,steps:[{label:"FFmpeg",sub:s("采集 / 推流","Capture"),gradient:"from-cyan-400 to-blue-500",target:"live_tiktok"},{label:"HDMI",sub:s("板载输出","SoC out"),gradient:"from-violet-500 to-fuchsia-500"},{label:"Android",sub:s("AOSP / 手机","AOSP"),gradient:"from-amber-400 to-orange-500",target:"android"}]}):null,(0,n.jsx)("div",{className:"rounded-2xl border border-cyan-500/25 bg-gradient-to-br from-cyan-500/[0.14] via-zinc-950/80 to-fuchsia-500/10 p-6 shadow-xl shadow-cyan-900/10",children:(0,n.jsx)("div",{className:"flex flex-wrap items-start gap-4",children:(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[(0,n.jsx)("div",{className:"flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-cyan-500/35 to-fuchsia-600/25 ring-1 ring-white/10",children:(0,n.jsx)(D.Z,{className:"h-5 w-5 text-cyan-200"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold tracking-tight text-white",children:s("TikTok 无人直播(单路)","TikTok unmanned (single lane)")}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-zinc-500",children:s("布局对齐 YouTube 单频道:直播开关 + 源站 + URL_config;无 stream key,输出走 HDMI 硬件链路。","Same layout as YouTube single: controls + URLs; no stream key — HDMI hardware path.")})]})]})})}),(0,n.jsx)("div",{className:"rounded-2xl border border-cyan-500/20 bg-cyan-500/[0.06] p-4 ring-1 ring-white/[0.04]",children:(0,n.jsx)("p",{className:"text-xs leading-relaxed text-cyan-100/90",children:s("HDMI 互斥:后端在「开始 / 重新开始」TikTok 或 obs*.sh(SRS 拉流上屏)时,会自动停止其它正在占用 HDMI 链路的同类进程;与 YouTube 推流互不干扰。","HDMI mutex: starting TikTok or obs*.sh stops other TikTok/OBS HDMI sinks; YouTube RTMP is unaffected.")})}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/10 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(ea.Z,{className:"h-4 w-4 text-cyan-300"}),s("X86 HDMI 采集状态","X86 HDMI capture status")]}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("这里直接显示主机是否识别到采集卡和 /dev/video 设备,可用于验证 ARM HDMI 进 X86 的链路。","Shows whether the host sees the capture card and /dev/video nodes for ARM-to-X86 HDMI ingest.")})]}),(0,n.jsx)("span",{className:"rounded-full px-3 py-1 text-[11px] font-semibold ring-1 ".concat(eh?"bg-emerald-500/20 text-emerald-200 ring-emerald-500/30":"bg-rose-500/15 text-rose-200 ring-rose-500/25"),children:eh?s("可推流","Ready"):s("未就绪","Not ready")})]}),(0,n.jsxs)("div",{className:"mt-4 grid gap-3 md:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/25 p-4 text-[11px] text-zinc-400",children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"device: "}),(0,n.jsx)("span",{className:"font-mono text-zinc-200",children:ep||"—"})]}),(0,n.jsxs)("p",{className:"mt-2",children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"video nodes: "}),(0,n.jsx)("span",{className:"font-mono text-zinc-200",children:((null==g?void 0:g.video_devices)||[]).join(", ")||"—"})]}),(0,n.jsxs)("p",{className:"mt-2",children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"usb matches: "}),(0,n.jsx)("span",{className:"text-zinc-300",children:((null==g?void 0:g.usb_capture_matches)||[]).length||0})]})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/25 p-4 text-[11px] text-zinc-400",children:[(0,n.jsx)("p",{className:"text-zinc-600",children:s("建议 FFmpeg","Suggested FFmpeg")}),(0,n.jsx)("p",{className:"mt-2 break-all font-mono text-zinc-200",children:(null==g?void 0:g.suggested_ffmpeg_cmd)||"—"}),(null==g?void 0:g.suggested_ffmpeg_cmd)?(0,n.jsxs)("button",{type:"button",onClick:()=>m(g.suggested_ffmpeg_cmd||""),className:"mt-3 inline-flex items-center gap-2 rounded-lg bg-cyan-500/15 px-3 py-2 text-xs font-medium text-cyan-100 ring-1 ring-cyan-500/25",children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),s("复制命令","Copy command")]}):null]})]}),((null==g?void 0:g.issues)||[]).length?(0,n.jsx)("ul",{className:"mt-4 list-inside list-disc space-y-1 text-[11px] text-amber-200/85",children:((null==g?void 0:g.issues)||[]).map(e=>(0,n.jsx)("li",{children:e},e))}):null]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-amber-500/20 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-amber-200/90",children:[(0,n.jsx)(B.Z,{className:"h-4 w-4"}),(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:s("直播开关","Live control")})]}),(0,n.jsx)("label",{className:"mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500",children:s("TikTok 进程(PM2)","TikTok PM2 process")}),(0,n.jsx)("select",{className:"mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white",value:r,onChange:e=>a(e.target.value),children:w.map(e=>(0,n.jsxs)("option",{value:e.pm2,children:[e.label," (",e.pm2,")"]},e.pm2))}),(0,n.jsx)("label",{className:"mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500",children:s("直播源","Video source")}),(0,n.jsxs)("select",{className:"mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white",value:N,onChange:e=>$(e.target.value),children:[(0,n.jsx)("option",{value:"ffmpeg",hidden:!0,children:"FFmpeg(抖音 / TikTok 等直播间 URL)"}),(0,n.jsx)("option",{value:"replay",hidden:!0,children:s("录播素材(本地上传)","VOD upload")}),(0,n.jsx)("option",{value:"srs",children:s("SRS(OBS 推流)","SRS (OBS)")})]}),"srs"===N?(0,n.jsx)("p",{className:"mt-2 text-[11px] leading-relaxed text-amber-200/85",children:s("此模式不显示 URL_config:请在 OBS 中填写下方 RTMP 推流地址;板端 SRS 拉流上屏仍可能占用 HDMI,与 TikTok 进程互斥规则不变。","URL_config is hidden: set the RTMP URL in OBS. SRS pull-to-HDMI may still mutex with TikTok per server rules.")}):null,(0,n.jsx)("div",{className:"mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3",children:[["start",s("开始直播","Start"),"bg-emerald-500/20 text-emerald-200 ring-emerald-500/30"],["stop",s("停止直播","Stop"),"bg-rose-500/15 text-rose-200 ring-rose-500/25"],["restart",s("重新开始","Restart"),"bg-amber-500/15 text-amber-200 ring-amber-500/25"]].map(e=>{let[t,s,l]=e;return(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>d(t),className:"rounded-xl px-4 py-3 text-sm font-medium ring-1 ".concat(l),children:s},t)})}),(0,n.jsxs)("p",{className:"mt-3 text-center text-[11px] text-zinc-500",children:[s("当前 HDMI 预设(备忘)","HDMI preset (memo)"),":"," ",(0,n.jsx)("span",{className:"font-mono text-cyan-300/90",children:em?s(em.labelZh,em.labelEn):T})]})]}),"replay"===N?(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/25 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(eo.Z,{className:"h-4 w-4 text-violet-300"}),s("录播素材","VOD library")]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsxs)("label",{className:"inline-flex cursor-pointer items-center gap-2 rounded-xl bg-violet-500/15 px-3 py-2 text-xs font-medium text-violet-100 ring-1 ring-violet-500/30",children:[(0,n.jsx)(ec.Z,{className:"h-3.5 w-3.5"}),(0,n.jsx)("span",{children:s("上传视频","Upload")}),(0,n.jsx)("input",{type:"file",accept:".mp4,.mkv,.ts,.flv,.mov,.m4v,.webm",className:"hidden",onChange:er})]}),(0,n.jsx)("button",{type:"button",disabled:ex||!r,onClick:()=>void ee(),className:"rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-xs text-zinc-300",children:s("刷新列表","Refresh")})]})]}),(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:s("文件保存在服务器 config/tiktok_replay/对应进程目录;点「开始直播」会写入 replayfile 行并启动 PM2 进程。停播请用上方「停止直播」。","Files under config/tiktok_replay/. Go live writes replayfile + starts PM2. Use Stop above to stop.")}),S?(0,n.jsx)("p",{className:"mt-4 text-xs text-zinc-500",children:s("加载中…","Loading…")}):0===k.length?(0,n.jsx)("p",{className:"mt-4 text-xs text-zinc-500",children:s("暂无文件,请先上传。","No files yet.")}):(0,n.jsx)("ul",{className:"mt-4 space-y-2",children:k.map(e=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center justify-between gap-2 rounded-xl border border-white/10 bg-black/30 px-3 py-2 text-xs text-zinc-300",children:[(0,n.jsx)("span",{className:"min-w-0 flex-1 truncate font-mono",children:e.name}),(0,n.jsxs)("span",{className:"shrink-0 text-zinc-500",children:[(e.size/1048576).toFixed(1)," MB"]}),(0,n.jsxs)("div",{className:"flex shrink-0 flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>void(async()=>{try{await Promise.resolve(u(e.replay_url,e.name))}catch(e){}})(),className:"rounded-lg bg-emerald-500/20 px-2 py-1 text-[11px] text-emerald-100 ring-1 ring-emerald-500/30",children:s("开始直播","Go live")}),(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>d("stop"),className:"rounded-lg bg-rose-500/15 px-2 py-1 text-[11px] text-rose-100 ring-1 ring-rose-500/25",children:s("停播","Stop")}),(0,n.jsxs)("button",{type:"button",disabled:ex,onClick:()=>void ei(e.name),className:"inline-flex items-center gap-1 rounded-lg bg-zinc-700/40 px-2 py-1 text-[11px] text-zinc-200",children:[(0,n.jsx)(ed.Z,{className:"h-3 w-3"}),s("删除","Del")]})]})]},e.name))})]}):null,"srs"===N?(0,n.jsxs)("div",{className:"rounded-2xl border border-emerald-500/25 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:s("SRS / OBS 推流","SRS / OBS ingest")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("OBS:设置 → 推流 → 服务选「自定义」,服务器填 RTMP 地址;串流密钥可与 SRS 应用配置一致(默认 live/livestream)。","OBS → Stream → Custom: RTMP URL as server; stream key per SRS app (default live/livestream).")}),(0,n.jsxs)("dl",{className:"mt-4 space-y-3 text-xs",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-500",children:s("RTMP 推流地址(OBS 服务器)","RTMP publish URL")}),(0,n.jsxs)("dd",{className:"mt-1 flex flex-wrap items-center gap-2 font-mono text-emerald-200/90",children:[(0,n.jsx)("span",{className:"break-all",children:b.srs_rtmp_publish||"—"}),b.srs_rtmp_publish?(0,n.jsx)("button",{type:"button",className:"shrink-0 text-cyan-300 hover:text-cyan-200",onClick:()=>m(b.srs_rtmp_publish),children:(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"})}):null]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-500",children:s("HTTP-FLV 预览","HTTP-FLV preview")}),(0,n.jsxs)("dd",{className:"mt-1 flex flex-wrap items-center gap-2 font-mono text-zinc-400",children:[(0,n.jsx)("span",{className:"break-all",children:b.srs_play_flv||b.srs_http||"—"}),b.srs_play_flv||b.srs_http?(0,n.jsx)("button",{type:"button",className:"shrink-0 text-cyan-300 hover:text-cyan-200",onClick:()=>m(b.srs_play_flv||b.srs_http),children:(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"})}):null]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-500",children:s("SRS 控制台","SRS web UI")}),(0,n.jsx)("dd",{className:"mt-1 font-mono text-zinc-400",children:(0,n.jsx)("a",{href:b.srs_http||"#",target:"_blank",rel:"noreferrer",className:"text-cyan-300 hover:underline",children:b.srs_http||"—"})})]})]})]}):null,(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(ea.Z,{className:"h-4 w-4 text-cyan-400"}),s("HDMI 硬件与时序","HDMI timing")]}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("点选一路作为现场备忘;与板端 ffmpeg/OBS 采集参数对齐。","Pick a preset as field memo; match capture settings.")}),(0,n.jsx)("div",{className:"mt-4 grid gap-3 md:grid-cols-3",children:ew.map(e=>{let t=L===e.id,l=T===e.id;return(0,n.jsxs)("button",{type:"button",onClick:()=>{M(t?null:e.id),E(e.id)},className:"rounded-2xl border p-4 text-left transition ".concat(l?"border-cyan-500/50 ring-1 ring-cyan-500/20":""," ").concat(t?"border-cyan-500/40 bg-cyan-500/10":"border-white/[0.08] bg-zinc-950/50 hover:border-white/15"),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(ea.Z,{className:"h-4 w-4 text-cyan-400"}),s(e.labelZh,e.labelEn)]}),(0,n.jsx)("p",{className:"mt-2 font-mono text-[11px] text-zinc-400",children:e.spec}),t?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:s(e.hintZh,e.hintEn)}):null]},e.id)})}),(0,n.jsxs)("div",{className:"mt-6 rounded-xl border border-white/5 bg-black/25 p-4",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-zinc-400",children:s("上线前检查清单(本地保存)","Pre-flight checklist (local)")}),(0,n.jsx)("ul",{className:"mt-3 space-y-2",children:[{id:"cable",zh:"HDMI 线材插紧、方向正确(如需转接头确认规格)",en:"HDMI cable seated; adapter specs OK"},{id:"thermal",zh:"长时间推流注意散热,过热会掉帧黑屏",en:"Thermal headroom for long runs"}].map(e=>(0,n.jsxs)("li",{className:"flex items-start gap-2 text-xs text-zinc-400",children:[(0,n.jsx)("input",{type:"checkbox",className:"mt-0.5 rounded border-white/20 bg-black/40",checked:!!V[e.id],onChange:t=>et({...V,[e.id]:t.target.checked})}),(0,n.jsx)("span",{children:s(e.zh,e.en)})]},e.id))}),(0,n.jsx)("label",{className:"mt-4 block text-[11px] text-zinc-500",children:s("HDMI / 走线备忘","HDMI / wiring notes")}),(0,n.jsx)("textarea",{className:"mt-1 min-h-[72px] w-full resize-y rounded-lg border border-white/10 bg-black/40 p-3 text-xs text-zinc-300",value:J,onChange:e=>es(e.target.value),spellCheck:!1,placeholder:s("接口、线长、显示器型号…","Ports, cable length, display model…")})]})]}),"ffmpeg"===N?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:s("直播地址列表 \xb7 URL_config.ini","URL_config.ini")}),(0,n.jsxs)("button",{type:"button",className:"inline-flex items-center gap-1 text-xs text-cyan-300 hover:text-cyan-200",onClick:()=>m(o),children:[(0,n.jsx)(U.Z,{className:"h-3.5 w-3.5"}),s("复制全文","Copy all")]})]}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:s("一行一个地址;可勾选自动从服务器刷新,或点「重新读取」手动同步。","One URL per line; enable auto-refresh or reload from server.")}),(0,n.jsx)("div",{className:"mt-2 flex flex-wrap items-center gap-4 text-xs text-zinc-400",children:(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:Z,onChange:e=>O(e.target.checked)}),s("每 8 秒自动从服务器刷新","Auto-refresh from server every 8s")]})}),H?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:H}):null,(0,n.jsx)("textarea",{className:"mt-4 min-h-[200px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300",value:o,onChange:e=>{F.current=!0,X(e.target.value)},spellCheck:!1}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>void en(),className:"rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-300",children:s("重新读取","Reload from server")}),(0,n.jsx)("button",{type:"button",disabled:ex,onClick:()=>void el(),className:"rounded-xl bg-cyan-500/20 px-4 py-2 text-sm font-medium text-cyan-100 ring-1 ring-cyan-500/30",children:s("保存 URL 配置","Save URL config")})]})]}):null,(0,n.jsx)(ev,{t:s,currentProc:r,fetchJson:h,urlListText:"ffmpeg"===N?o:"",keySuffixUi:"",showKeyRow:!1})]})}var eS=s(5468),e_=s(9397),eC=s(90);let eR="live-hub-youtube-pro-v2",eP="youtube2__",eL=/[^a-zA-Z0-9_.-]+/g,eM=new Set(["youtube","douyin_youtube","tiktok","obs","web"]);function eT(e){return(e||"").trim().replace(eL,"_")}function eU(e,t){let s=eT(e);return!s||eM.has(s)||s===eP?eK(t):s.startsWith(eP)?s:eK(s)}function eE(e){return eU(String(e.pm2Name||""),String(e.id||""))}function eI(e){if(!e||"object"!=typeof e)return null;let t=String(e.id||"").trim();if(!t)return null;let s=String(e.name||"").trim()||t;return{id:t,name:s,streamKeySuffix:"string"==typeof e.streamKeySuffix?e.streamKeySuffix:void 0,streamKey:"string"==typeof e.streamKey?e.streamKey:void 0,urlLines:"string"==typeof e.urlLines?e.urlLines:void 0,pm2Name:eU("string"==typeof e.pm2Name?e.pm2Name:"",t),notes:"string"==typeof e.notes?e.notes:void 0}}function eD(e){if(!e)return[];try{let t=JSON.parse(e);if(!Array.isArray(t))return[];return t.map(e=>eI(e)).filter(e=>null!==e)}catch(e){return[]}}function eA(e){window.localStorage.setItem(eR,JSON.stringify(e))}let eZ=["/hub/youtube_pro_channels","/youtube_pro_channels"];async function eO(e){for(let s of eZ)try{var t;let n=await e(s);return{fetched:!0,channels:(t=n.channels,Array.isArray(t)?t.map(e=>eI(e)).filter(e=>null!==e):[])}}catch(e){}return{fetched:!1,channels:[]}}async function eH(e,t){let s=null;for(let n of eZ)try{await e(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({channels:t})});return}catch(e){s=e instanceof Error?e:Error(String(e))}throw null!=s?s:Error("youtube_pro_channels sync failed")}function eB(){return"ch_".concat(Date.now().toString(36),"_").concat(Math.random().toString(36).slice(2,7))}function eK(e){return"".concat(eP).concat(eT(e)||"channel")}function eF(e){return/youtube/i.test(e.script)||/youtube/i.test(e.pm2)}function eW(e){return(e.split("/").pop()||e).replace(/\.[^.]+$/,"")}function eY(e){var t;return!!e&&(/youtube/i.test(e.pm2)||/youtube/i.test(null!==(t=e.script)&&void 0!==t?t:""))}function eJ(e,t){let s=((null==t?void 0:t.business_status)||"").trim().toLowerCase();return(null==t?void 0:t.is_pushing)||"streaming"===s?0:eX(null==t?void 0:t.process_status)?1:"youtube"===e.pm2.trim().toLowerCase()?2:"youtube"===eW(e.script).trim().toLowerCase()?3:10}let eG="live-hub-youtube-mode-v1",eV=new Set(["youtube","douyin_youtube","tiktok","obs","web"]);function eq(e){var t,s,n;return{name:e.name,streamKey:null!==(t=e.streamKey)&&void 0!==t?t:"",pm2Name:null!==(s=e.pm2Name)&&void 0!==s?s:eK(e.id),notes:null!==(n=e.notes)&&void 0!==n?n:""}}function eX(e){return/^(online|running)$/i.test((e||"").trim())}function e$(e,t){let s=((null==e?void 0:e.business_status)||"").trim().toLowerCase();return"ready"===s?t("已配置","Ready"):"streaming"===s?t("推流中","Pushing"):"waiting_source"===s?t("等待上游","Waiting source"):"source_live"===s?t("源已开播,转推未起","Source live, relay down"):"monitoring"===s?t("监控中","Monitoring"):"misconfigured"===s?t("密钥异常","Key invalid"):"stale"===s?t("心跳过期","Stale"):"error"===s?t("异常","Error"):eX(null==e?void 0:e.process_status)?t("运行中","Running"):((null==e?void 0:e.process_status)||"").trim()||t("未运行","Idle")}function eQ(e){return e.split(/\r?\n/).map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"))}function e0(e,t){return eQ(e).length>0&&0===eQ(t).length}function e1(e){let{kind:t,busyKind:s,targetPm2:l,busy:i,online:r,label:a,className:o,baseLock:c,onRun:d,notify:x,t:u,compact:m}=e,h=function(e){if(!(null==e?void 0:e.startsWith("proc:")))return null;let t=e.slice(5),s=t.indexOf(":");if(s<=0)return null;let n=t.slice(0,s),l=t.slice(s+1);return l&&["start","stop","restart"].includes(n)?{action:n,pm2:l}:null}(i),p=h&&h.pm2===l,b=null!=s?s:t,g=!!(p&&h.action===b),f=!!(p&&h.action!==b),y="start"===t&&r,w="stop"===t&&!r,N="restart"===t&&!r,j=y||w||N;return(0,n.jsxs)("button",{type:"button",onClick:()=>{if(!g){if(f){x(u("请等待当前操作完成","Wait for the current action to finish"));return}if(y){x(u("已在直播中,无需重复开始","Already live"));return}if(w){x(u("当前未在直播,无法停止","Not live — cannot stop"));return}if(N){x(u("进程未运行时请使用「开始直播」","Use Start when the process is not running"));return}c||d()}},className:"relative overflow-hidden rounded-xl ring-1 transition ".concat(m?"min-h-[2rem] px-3 py-1.5 text-xs font-medium":"min-h-[2.75rem] px-4 py-3 text-sm font-medium"," ").concat(o," ").concat(j||c||g||f?"cursor-not-allowed":""," ").concat(j&&!g?"opacity-45":""," ").concat(f?"opacity-35":""," ").concat(g?"ring-violet-400/40":""),children:[g?(0,n.jsx)("span",{className:"absolute inset-0 flex items-center justify-center bg-black/25 backdrop-blur-[2px]",children:(0,n.jsx)(v.Z,{className:"".concat(m?"h-4 w-4":"h-6 w-6"," animate-spin text-white")})}):null,(0,n.jsxs)("span",{className:"inline-flex items-center justify-center gap-1.5 ".concat(g?"invisible":""),children:[j?(0,n.jsx)(eS.Z,{className:"".concat(m?"h-3 w-3":"h-4 w-4"," shrink-0 opacity-90"),"aria-hidden":!0}):null,a]})]})}function e5(e){var t,s,l,i,r;let{t:a,busy:o,entries:d,currentProc:x,setCurrentProc:u,urlConfig:m,setUrlConfig:h,onRunProcess:p,onSaveUrlConfig:b,fetchJson:g,liveProcesses:f,notify:w,onNavigate:N,quickLinks:j}=e,k=(0,_.useMemo)(()=>d.filter(eF),[d]),z=(0,_.useMemo)(()=>(function(e,t){let s=e.filter(eF),n=s.filter(e=>eF(e)&&e.pm2.trim()===eW(e.script).trim()),l=n.length?[...n]:s.length?[...s]:[...e],i=new Set(l.map(e=>e.pm2.trim()));for(let e of t.filter(eY)){var r,a,o,c;let t=e.pm2.trim();if(!t||i.has(t))continue;let n=(e.business_status||"").trim().toLowerCase();if(!e.is_pushing&&"streaming"!==n&&!eX(e.process_status))continue;let d=s.find(e=>e.pm2.trim()===t);l.push(null!=d?d:{pm2:t,script:null!==(o=null!==(a=e.script)&&void 0!==a?a:null===(r=s[0])||void 0===r?void 0:r.script)&&void 0!==o?o:"youtube.py",label:null!==(c=e.label)&&void 0!==c?c:t}),i.add(t)}return l})(k.length?k:d,f),[d,f,k]),S=(0,_.useMemo)(()=>(function(e,t){if(!e.length)return"";let s=new Map(t.filter(eY).map(e=>[e.pm2.trim(),e])),n=e[0],l=eJ(n,s.get(n.pm2.trim()));for(let t of e.slice(1)){let e=eJ(t,s.get(t.pm2.trim()));e"youtube"===e.pm2.trim().toLowerCase());if(n)return n.pm2;let l=e.find(e=>"youtube"===eW(e.script).trim().toLowerCase());return l?l.pm2:null!==(s=null===(t=e[0])||void 0===t?void 0:t.pm2)&&void 0!==s?s:""}(z),[f,z]),[C,R]=(0,_.useState)("single"),[P,L]=(0,_.useState)([]),[M,T]=(0,_.useState)(""),[U,E]=(0,_.useState)(""),[I,D]=(0,_.useState)({key:"",rtmps:!0,bitrate:"",fastAudio:!1}),[A,O]=(0,_.useState)(null),[H,K]=(0,_.useState)(!1),[F,W]=(0,_.useState)(""),[Y,J]=(0,_.useState)(!0),[G,V]=(0,_.useState)(!1),[q,X]=(0,_.useState)(!1),[$,Q]=(0,_.useState)(null),[ee,et]=(0,_.useState)({}),[es,en]=(0,_.useState)(!1),[el,ei]=(0,_.useState)(null),[er,ea]=(0,_.useState)(0),eo=(0,_.useRef)(!1),ec=(0,_.useRef)(m),ef=(0,_.useRef)(F),ey=(0,_.useRef)(x),ew=(0,_.useRef)(0),eN=(0,_.useRef)(0),ej=(0,_.useCallback)(e=>{ec.current=e,h(e)},[h]),ek=(0,_.useCallback)(e=>{ef.current=e,W(e)},[]);(0,_.useEffect)(()=>{eo.current=!1},[x]),(0,_.useEffect)(()=>{ey.current=x},[x]),(0,_.useEffect)(()=>{ec.current=m},[m]),(0,_.useEffect)(()=>{ef.current=F},[F]);let ez=(0,_.useCallback)(async()=>{let e=ey.current.trim();if(!e)return;let t=++ew.current;try{var s,n,l;let i=new URLSearchParams({process:e,_ts:String(Date.now())}),r=await g("/get_url_config?".concat(i));if(t!==ew.current||e!==ey.current.trim())return;let a=null!==(s=r.content)&&void 0!==s?s:"";if(eo.current)return;if("single"===C)ej(a);else{let e=null!==(l=null===(n=P.find(e=>e.id===M))||void 0===n?void 0:n.urlLines)&&void 0!==l?l:"";if(e0(e,a)){ek(e);return}ek(a),M&&L(e=>{let t=e.map(e=>e.id===M?{...e,urlLines:a}:e);return eA(t),t})}}catch(e){}},[M,ek,ej,P,g,C]);(0,_.useEffect)(()=>{if(!x||!Y)return;let e=window.setInterval(()=>{eo.current||ez()},8e3);return()=>clearInterval(e)},[x,Y,ez]);let eS=async()=>{let e=ey.current.trim();if(!e)return;V(!0),Q(null),eo.current=!1;let t=++ew.current;try{var s,n,l;let i=new URLSearchParams({process:e,_ts:String(Date.now())}),r=await g("/get_url_config?".concat(i));if(t!==ew.current||e!==ey.current.trim())return;let o=null!==(s=r.content)&&void 0!==s?s:"";if(eo.current){Q(a("检测到本地未保存修改,已保留当前草稿","Kept the local unsaved draft"));return}if("single"===C)ej(o);else{let e=null!==(l=null===(n=P.find(e=>e.id===M))||void 0===n?void 0:n.urlLines)&&void 0!==l?l:"";if(e0(e,o)){ek(e),Q(a("服务器暂无已保存 URL,已保留本地草稿","Server has no saved URLs, kept the local draft"));return}ek(o),M&&L(e=>{let t=e.map(e=>e.id===M?{...e,urlLines:o}:e);return eA(t),t})}Q(a("已从服务器读取 URL_config","Reloaded URL_config from server"))}catch(s){if(t!==ew.current||e!==ey.current.trim())return;Q(s.message)}finally{t===ew.current&&e===ey.current.trim()&&V(!1)}};(0,_.useEffect)(()=>{try{let e=window.localStorage.getItem(eG);("pro"===e||"single"===e)&&R(e)}catch(e){}},[]),(0,_.useEffect)(()=>{let e=!1;return(async()=>{try{let t=await eO(g);if(t.fetched&&t.channels.length&&!e){L(t.channels),eA(t.channels);return}}catch(e){}if(e)return;let t=function(){let e=window.localStorage.getItem(eR);if(!e&&(e=window.localStorage.getItem("live-hub-youtube-pro-v1"))){let t=eD(e);if(t.length)return window.localStorage.setItem(eR,JSON.stringify(t)),t}return eD(e)}(),s=t.length>0?t:(()=>{let e=eB();return[{id:e,name:"线路 1",streamKey:"",urlLines:"",pm2Name:eK(e),notes:""}]})();L(s),t.length||eA(s)})(),()=>{e=!0}},[g]),(0,_.useEffect)(()=>{if(!P.length){M&&T("");return}M&&P.some(e=>e.id===M)||T(P[0].id)},[P,M]);let eP=(0,_.useCallback)(e=>f.find(t=>t.pm2===e),[f]),eL=(0,_.useCallback)(e=>{var t;return null===(t=eP(e))||void 0===t?void 0:t.process_status},[eP]),eM=eP(x),eU=(0,_.useMemo)(()=>{var e,t;return!!x&&(/youtube/i.test(x)||/youtube/i.test(null!==(e=null==eM?void 0:eM.script)&&void 0!==e?e:"")||/youtube/i.test(null!==(t=null==eM?void 0:eM.label)&&void 0!==t?t:""))},[x,eM]);(0,_.useEffect)(()=>{"single"!==C||!S||x&&eU||u(S)},[x,eU,C,S,u]);let eI=(0,_.useCallback)(e=>{L(e),eA(e)},[]),eZ=(0,_.useCallback)(async e=>{await eH(g,e)},[g]),e5=(0,_.useCallback)(e=>{eI(e),eZ(e).catch(e=>{w("".concat(a("多频道列表未同步到服务器","Channel list not saved on server"),": ").concat(e.message))})},[eI,w,eZ,a]),e2=P.find(e=>e.id===M)||P[0],e3=(0,_.useMemo)(()=>{var e;return e2?null!==(e=ee[e2.id])&&void 0!==e?e:eq(e2):null},[e2,ee]);(0,_.useEffect)(()=>{e2&&et(e=>e[e2.id]?e:{...e,[e2.id]:eq(e2)})},[e2]),(0,_.useEffect)(()=>{ei(null)},[M]);let e4=(0,_.useCallback)((e,t)=>{e2&&(et(s=>{var n;return{...s,[e2.id]:{...null!==(n=s[e2.id])&&void 0!==n?n:eq(e2),[e]:t}}}),ei(null))},[e2]),e6=e2?eE(e2):"",e8=e2&&e3?eE({id:e2.id,pm2Name:e3.pm2Name}):"",e9=!!e2&&!!e3&&e8!==e6,e7=(0,_.useMemo)(()=>{if(!e2||!e3)return{ok:!1,message:a("请选择线路","Pick a lane"),normalizedName:"",normalizedPm2:"",normalizedStreamKey:"",normalizedNotes:""};let e=e3.name.trim()||"".concat(a("线路","Ch")," ").concat(P.findIndex(e=>e.id===e2.id)+1),t=eE({id:e2.id,pm2Name:e3.pm2Name});return t?eV.has(t)?{ok:!1,message:a("该进程名保留给系统模块,请换一个","This PM2 name is reserved"),normalizedName:e,normalizedPm2:t,normalizedStreamKey:e3.streamKey.trim(),normalizedNotes:e3.notes.trim()}:P.find(e=>e.id!==e2.id&&eE(e)===t)?{ok:!1,message:a("该进程名已被其它线路占用","Another lane already uses this PM2 name"),normalizedName:e,normalizedPm2:t,normalizedStreamKey:e3.streamKey.trim(),normalizedNotes:e3.notes.trim()}:{ok:!0,message:"",normalizedName:e,normalizedPm2:t,normalizedStreamKey:e3.streamKey.trim(),normalizedNotes:e3.notes.trim()}:{ok:!1,message:a("进程名不能为空","PM2 name is required"),normalizedName:e,normalizedPm2:t,normalizedStreamKey:e3.streamKey.trim(),normalizedNotes:e3.notes.trim()}},[e2,e3,P,a]),te=(0,_.useMemo)(()=>{if(!e2||!e3)return!1;let e=eq(e2);return e3.name!==e.name||e3.streamKey!==e.streamKey||eT(e3.pm2Name)!==eT(e.pm2Name)||e3.notes!==e.notes},[e2,e3]),tt=(0,_.useCallback)(e=>{var t,s,n;if("single"===e&&"pro"===C&&e2){let e=ef.current;e!==(null!==(t=e2.urlLines)&&void 0!==t?t:"").trim()&&e5(P.map(t=>t.id===e2.id?{...t,urlLines:e}:t))}if("pro"===e&&P.length){let e=P[0],t=ec.current.trim(),l=eE(e),i=[{...e,streamKey:I.key.trim()||e.streamKey||"",urlLines:t||e.urlLines||"",pm2Name:l},...P.slice(1)];e5(i);let r=null!==(s=i.find(e=>e.id===M))&&void 0!==s?s:i[0];ek((null!==(n=null==r?void 0:r.urlLines)&&void 0!==n?n:"").trim()||t)}R(e);try{window.localStorage.setItem(eG,e)}catch(e){}},[C,e2,P,ek,I.key,M,e5]),ts=(0,_.useCallback)(e=>{var t,s;let n=ef.current;e2&&"pro"===C&&n!==(null!==(t=e2.urlLines)&&void 0!==t?t:"").trim()&&e5(P.map(e=>e.id===e2.id?{...e,urlLines:n}:e)),ek((null!==(s=e.urlLines)&&void 0!==s?s:"").trim()),T(e.id),u(eE(e))},[e2,ek,C,P,u,e5]);(0,_.useEffect)(()=>{if("pro"!==C||!M)return;let e=P.find(e=>e.id===M);e&&u(eE(e))},[C,M,P,u]);let tn=(0,_.useCallback)(async()=>{let e=ey.current.trim();if(!e)return;let t=++eN.current;K(!0),O(null);try{var s;let n=new URLSearchParams({process:e,_ts:String(Date.now())}),l=await g("/get_config?".concat(n));if(t!==eN.current||e!==ey.current.trim())return;let i=null!==(s=l.content)&&void 0!==s?s:"";E(i),D(ep(i))}catch(s){if(t!==eN.current||e!==ey.current.trim())return;O(s.message)}finally{t===eN.current&&e===ey.current.trim()&&K(!1)}},[g]);(0,_.useEffect)(()=>{x&&(ez(),tn(),ea(e=>e+1))},[M,x,tn,C,ez]);let tl=(0,_.useCallback)(async()=>{var e;if(!e2||!e3)throw Error(a("请选择线路","Pick a lane"));if(!e7.ok)throw Error(e7.message);let t=ef.current,s=P.map(e=>e.id===e2.id?{...e,name:e7.normalizedName,streamKey:e7.normalizedStreamKey,pm2Name:e7.normalizedPm2,notes:e7.normalizedNotes,urlLines:t}:e);return eI(s),await eZ(s),et(e=>({...e,[e2.id]:{name:e7.normalizedName,streamKey:e7.normalizedStreamKey,pm2Name:e7.normalizedPm2,notes:e7.normalizedNotes}})),{next:s,savedLane:null!==(e=s.find(e=>e.id===e2.id))&&void 0!==e?e:{...e2,name:e7.normalizedName,streamKey:e7.normalizedStreamKey,pm2Name:e7.normalizedPm2,notes:e7.normalizedNotes,urlLines:t},pm2:e7.normalizedPm2}},[e2,e3,e7,eI,P,eZ,a]),ti=(0,_.useCallback)(async()=>{if(e2){en(!0),ei(null);try{let e=await tl();u(e.pm2),ei(a("线路设置已保存","Lane settings saved"))}catch(t){let e=t.message;ei(e),w(e)}finally{en(!1)}}},[e2,w,tl,u,a]),tr=async function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:ey.current,s=t.trim();if(!s){O(a("请选择进程","Pick a process"));return}K(!0),O(null);try{let t=new URLSearchParams({process:s});await g("/save_config?".concat(t),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:e})}),E(e),O(a("youtube.ini 已保存","youtube.ini saved"))}catch(e){O(e.message)}finally{K(!1)}},ta=async()=>{let e=eg(I);await tr(e)},to=async()=>{K(!0),O(null);try{var e,t;let s=U||eg(I),n=await g("/config_optimize",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({root:"app-config",path:(t=ey.current,"youtube.".concat(t.replace(/[^a-zA-Z0-9_.-]/g,"_"),".ini")),content:s,action:"youtube_balanced_preset"})}),l=null!==(e=n.content)&&void 0!==e?e:s;E(l),D(ep(l)),O(n.message||a("已应用 YouTube 预设","Applied YouTube preset"))}catch(e){O(e.message)}finally{K(!1)}},tc=(0,_.useMemo)(()=>{var e,t;if("single"===C)return em("key = ".concat(I.key));let s=null!==(t=null!==(e=null==e3?void 0:e3.streamKey)&&void 0!==e?e:null==e2?void 0:e2.streamKey)&&void 0!==t?t:"";return em("key = ".concat(s))},[C,I.key,null==e2?void 0:e2.streamKey,null==e3?void 0:e3.streamKey]),td=async()=>{if(e2)try{en(!0),ei(null),ew.current+=1;let e=ef.current,t=await tl();u(t.pm2),await Promise.resolve(b(e,t.pm2)),eo.current=!1,ei(a("线路与地址已保存","Lane settings and URLs saved"))}catch(t){let e=t instanceof Error?t.message:String(t);ei(e),w(e)}finally{en(!1)}},tx=async()=>{let e=ey.current.trim();if(!e){w(a("请选择进程","Pick a process"));return}try{ew.current+=1,await Promise.resolve(b(ec.current,e)),eo.current=!1}catch(e){}},tu=async()=>{let e="single"===C?ec.current:ef.current;X(!0),Q(null);try{var t;let s=await g("/config_optimize",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({root:"app-config",path:eb(ey.current),content:e,action:"dedupe_urls"})}),n=null!==(t=s.content)&&void 0!==t?t:e;"single"===C?ej(n):ek(n),eo.current=!0,Q(s.message||a("已去重当前 URL 列表","Deduplicated current URL list"))}catch(e){Q(e.message)}finally{X(!1)}},tm=async()=>{if(!e2||!e3)return;let e=ep(U||eg(I)),t=eg({key:e3.streamKey.trim(),rtmps:e.rtmps,bitrate:e.bitrate,fastAudio:e.fastAudio});en(!0),ei(null);try{let e=await tl();u(e.pm2),await tr(t,e.pm2),ei(a("线路设置与 youtube.ini 已保存","Lane settings and youtube.ini saved"))}catch(t){let e=t.message;ei(e),w(e)}finally{en(!1)}},th="single"===C?m:F,tp=(0,_.useMemo)(()=>eQ(th).length,[th]),tb=(0,_.useMemo)(()=>eh(th).length,[th]),tg=(0,_.useMemo)(()=>(0,eC.O0)(j),[j]),tf=(0,_.useMemo)(()=>(0,eC.U_)(tg,"pro"===C&&e2?P.findIndex(e=>e.id===e2.id):0),[e2,P,C,tg]),tv=tf.link?(0,ex.p)(tf.link.url):(0,ex.p)("http://live.local:9200/"),ty=(0,_.useMemo)(()=>(0,eC.Tc)(tg),[tg]),tw=(0,_.useMemo)(()=>{var e;return[null===(e=tf.link)||void 0===e?void 0:e.url,null==j?void 0:j.chromium_remote_debug,null==j?void 0:j.srs_api].filter(e=>!!e)},[j,null===(t=tf.link)||void 0===t?void 0:t.url]),tN=(0,_.useCallback)(async e=>{let t=e2?eE(e2):"";return e2&&e===t?await tl():(eI(P),await eZ(P),{next:P,savedLane:null!=e2?e2:null,pm2:e})},[e2,eI,P,tl,eZ]),tj=(0,_.useCallback)(async(e,t)=>{let s=!!e2&&eE(e2)===t;if("stop"!==e){var n,l;let e=P,s=t;try{let n=await tN(t);e=n.next,s=n.pm2}catch(e){w("".concat(a("当前线路保存失败","Failed to save the active lane"),": ").concat(e.message));return}let i=e.find(e=>eE(e)===s),r=null!==(n=null==i?void 0:i.urlLines)&&void 0!==n?n:"";if(!(null!==(l=null==i?void 0:i.streamKey)&&void 0!==l?l:"").trim()){w(a("请先填写当前线路的推流密钥","Fill the stream key before starting"));return}if(!eQ(r).length){w(a("请先填写当前线路的直播地址","Fill the source URLs before starting"));return}t=s}s&&u(t),p(e,t)},[e2,P,tN,w,p,u,a]),tk=!!o||H||G||q||es,tz=eX(eL(x)),tS=(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap items-center gap-4 text-xs text-zinc-400",children:[(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:Y,onChange:e=>J(e.target.checked)}),a("每 8 秒自动从服务器刷新","Auto-refresh from server every 8s")]}),(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void eS(),className:"rounded-lg border border-white/10 px-3 py-1.5 text-zinc-200 hover:bg-white/5",children:a("手动重新读取","Reload from server")}),(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void tu(),className:"rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-1.5 text-cyan-100 hover:bg-cyan-500/15",children:q?a("去重中...","Deduplicating..."):a("智能去重","Deduplicate")})]});return(0,n.jsxs)("div",{className:"mx-auto max-w-6xl space-y-6",children:[N?(0,n.jsx)(eu,{t:a,title:a("YouTube 转播链路","YouTube relay chain"),subtitle:a("与「网络」页相同风格的链路示意:代理 → 编码推流 → 浏览器侧操作工作室。","Same visual language as Network: proxy → encode → browser studio."),onNavigate:N,steps:[{label:"ShellCrash",sub:a("透明代理","Proxy"),gradient:"from-violet-500 to-fuchsia-500",target:"network"},{label:"FFmpeg",sub:a("推流 / 转码","Stream"),gradient:"from-cyan-400 to-blue-500",target:"live_youtube"},{label:"Neko",sub:tf.link?"".concat(a("Chromium 工作室","Chromium studio")," \xb7 ").concat(tf.link.label):a("Chromium 工作室","Chromium studio"),gradient:"from-emerald-400 to-teal-500",openUrl:tv}]}):null,(0,n.jsx)("div",{className:"rounded-2xl border border-violet-500/25 bg-gradient-to-br from-violet-500/[0.12] via-zinc-950/80 to-cyan-500/5 p-6 shadow-xl shadow-violet-900/10",children:(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-4",children:[(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[(0,n.jsx)("div",{className:"flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-red-500/30 to-violet-600/30 ring-1 ring-white/10",children:(0,n.jsx)(c.Z,{className:"h-5 w-5 text-red-200"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("h2",{className:"text-lg font-semibold tracking-tight text-white",children:a("YouTube 无人直播","YouTube unmanned live")}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-zinc-500",children:a("单路一条流;多路时每条线路独立保存自己的密钥、URL 列表和 PM2 任务。填好后保存,再点「开始」。Neko 浏览器仅作辅助工作室,不再阻塞推流。","Single lane or multi-lane: every lane keeps its own key, URL list, and PM2 task. Save, then Start. Neko is optional browser tooling and no longer blocks streaming.")})]})]}),(0,n.jsxs)("div",{className:"flex rounded-xl border border-white/10 bg-black/30 p-1 ".concat(""),"aria-hidden":!1,children:[(0,n.jsx)("button",{type:"button",onClick:()=>tt("single"),className:"rounded-lg px-4 py-2 text-xs font-medium transition ".concat("single"===C?"bg-violet-500/25 text-white":"text-zinc-500 hover:text-zinc-300"),children:a("单频道","Single")}),(0,n.jsx)("button",{type:"button",onClick:()=>tt("pro"),className:"rounded-lg px-4 py-2 text-xs font-medium transition ".concat("pro"===C?"bg-violet-500/25 text-white":"text-zinc-500 hover:text-zinc-300"),children:a("多频道 Pro","Multi Pro")})]})]})}),tw.length?(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[tf.link?(0,n.jsx)("a",{href:tv,target:"_blank",rel:"noreferrer",className:"rounded-lg border border-emerald-500/20 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-100 ring-1 ring-emerald-500/20",children:a("打开当前线路 Neko 工作室","Open lane Neko studio")}):null,tg.length>1?(0,n.jsx)("div",{className:"flex flex-wrap gap-2",children:tg.map(e=>{var t;return(0,n.jsxs)("a",{href:(0,ex.p)(e.url),target:"_blank",rel:"noreferrer",className:"rounded-lg border px-3 py-2 text-xs ring-1 ".concat((null===(t=tf.link)||void 0===t?void 0:t.id)===e.id?"border-emerald-400/30 bg-emerald-500/15 text-emerald-50 ring-emerald-400/25":"border-white/10 bg-white/5 text-zinc-200 ring-white/10"),children:[e.label,e.port?" :".concat(e.port):""]},e.key)})}):null,(null==j?void 0:j.chromium_remote_debug)?(0,n.jsx)("a",{href:(0,ex.p)(j.chromium_remote_debug),target:"_blank",rel:"noreferrer",className:"rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-2 text-xs text-cyan-100 ring-1 ring-cyan-500/20",children:a("打开 Chromium 调试","Open Chromium debug")}):null,(null==j?void 0:j.srs_api)?(0,n.jsx)("a",{href:(0,ex.p)(j.srs_api),target:"_blank",rel:"noreferrer",className:"rounded-lg border border-violet-500/20 bg-violet-500/10 px-3 py-2 text-xs text-violet-100 ring-1 ring-violet-500/20",children:a("打开 SRS API","Open SRS API")}):null]}):null,(0,n.jsxs)("div",{className:"rounded-2xl border border-amber-500/20 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-amber-200/90",children:[(0,n.jsx)(B.Z,{className:"h-4 w-4"}),(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("直播开关","Live control")})]}),"single"===C?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("label",{className:"mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500",children:a("转播任务","Relay task")}),(0,n.jsxs)("select",{className:"mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white",value:x,onChange:e=>{let t=e.target.value;ey.current=t,u(t)},children:[x&&!z.some(e=>e.pm2===x)?(0,n.jsxs)("option",{value:x,children:[x,eM?" (".concat(e$(eM,a),")"):""]}):null,z.map(e=>(0,n.jsxs)("option",{value:e.pm2,children:[function(e,t){let s=eW(e.script).toLowerCase();return s.startsWith("douyin_youtube")?t("抖音→YouTube","Douyin → YouTube"):s.startsWith("youtube")?t("YouTube","YouTube"):e.label}(e,a)," (",e.pm2,")"]},e.pm2))]}),(0,n.jsxs)("div",{className:"mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3",children:[(0,n.jsx)(e1,{kind:"start",targetPm2:x,busy:o,online:tz,label:a("开始直播","Start"),className:"bg-emerald-500/20 text-emerald-200 ring-emerald-500/30",baseLock:!1,onRun:()=>p("start",x),notify:w,t:a}),(0,n.jsx)(e1,{kind:"stop",targetPm2:x,busy:o,online:tz,label:a("停止直播","Stop"),className:"bg-rose-500/15 text-rose-200 ring-rose-500/25",baseLock:!1,onRun:()=>p("stop",x),notify:w,t:a}),(0,n.jsx)(e1,{kind:"restart",targetPm2:x,busy:o,online:tz,label:a("重新开始","Restart"),className:"bg-amber-500/15 text-amber-200 ring-amber-500/25",baseLock:!1,onRun:()=>p("restart",x),notify:w,t:a})]}),(0,n.jsxs)("p",{className:"mt-3 text-center text-xs text-zinc-400",children:[a("当前状态","Current state"),": ",e$(eM,a)]}),(0,n.jsxs)("p",{className:"mt-3 text-center font-mono text-[11px] text-zinc-600",children:["key ",a("尾码","suffix"),": ",tc||"—"]})]}):(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("div",{className:"mt-4 rounded-xl border border-cyan-500/25 bg-gradient-to-br from-cyan-500/[0.1] via-zinc-950/50 to-violet-500/[0.06] p-4 ring-1 ring-white/[0.04]",children:[(0,n.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wider text-cyan-200/90",children:a("Pro 转播实况","Pro relay status")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:a("对齐桌面端:每路独立 URL / youtube 配置文件;点左侧信息切换编辑,右侧控制进程。","Per-lane config files like desktop; click row info to edit, use right-side controls for PM2.")}),ty?(0,n.jsxs)("p",{className:"mt-2 text-[11px] text-zinc-500",children:[a("Neko 实例","Neko instances"),": ",ty]}):null,(0,n.jsx)("div",{className:"mt-3 max-h-[min(24rem,55vh)] space-y-2 overflow-y-auto pr-1",children:P.map(e=>{var t,s,l;let i=eE(e),r=eP(i),c=eL(i),d=eQ((null!==(t=e.urlLines)&&void 0!==t?t:"").trim()),x=eh((null!==(s=e.urlLines)&&void 0!==s?s:"").trim()),u=x[0],m=em("key = ".concat(null!==(l=e.streamKey)&&void 0!==l?l:"")),h=M===e.id,p=eX(c),b=P.findIndex(t=>t.id===e.id),g=(0,eC.U_)(tg,b).link;return(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2 rounded-lg border px-3 py-2.5 text-left text-xs transition sm:flex-nowrap ".concat(h?"border-violet-500/45 bg-violet-500/[0.1]":"border-white/10 bg-black/30 hover:border-white/18"),children:[(0,n.jsxs)("button",{type:"button",className:"min-w-0 flex-1 text-left",onClick:()=>{ey.current=eE(e),ts(e)},children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsx)("span",{className:"font-medium text-zinc-100",children:e.name}),(0,n.jsx)("span",{className:"shrink-0 rounded-md px-2 py-0.5 text-[10px] font-medium ring-1 ".concat(function(e){let t=((null==e?void 0:e.business_status)||"").trim().toLowerCase();return"ready"===t?"bg-sky-500/15 text-sky-100 ring-sky-500/25":"streaming"===t?"bg-emerald-500/15 text-emerald-200 ring-emerald-500/30":"waiting_source"===t||"monitoring"===t?"bg-amber-500/15 text-amber-100 ring-amber-500/25":"source_live"===t?"bg-sky-500/15 text-sky-100 ring-sky-500/25":"misconfigured"===t||"error"===t||"stale"===t?"bg-rose-500/15 text-rose-100 ring-rose-500/25":eX(null==e?void 0:e.process_status)?"bg-emerald-500/15 text-emerald-200 ring-emerald-500/30":"bg-zinc-600/20 text-zinc-400 ring-zinc-500/25"}(r)),children:e$(r,a)}),g?(0,n.jsx)("span",{className:"shrink-0 rounded-md bg-emerald-500/15 px-2 py-0.5 text-[10px] font-medium text-emerald-100 ring-1 ring-emerald-500/25",children:g.label}):null]}),(0,n.jsxs)("div",{className:"mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 font-mono text-[10px] text-zinc-500",children:[(0,n.jsxs)("span",{children:["key …",m||"—"]}),(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"}),(0,n.jsx)("span",{className:"truncate",title:i,children:i}),(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"}),(0,n.jsxs)("span",{children:["URL ",d.length]}),(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"}),(0,n.jsxs)("span",{children:["DY ",x.length]})]}),u?(0,n.jsx)("a",{href:u,target:"_blank",rel:"noreferrer",className:"mt-1 block max-w-full truncate text-cyan-300/90 underline-offset-2 hover:underline",onClick:e=>e.stopPropagation(),title:u,children:u.replace(/^https?:\/\//,"")}):(0,n.jsx)("span",{className:"mt-1 block text-zinc-600",children:"—"})]}),(0,n.jsxs)("div",{className:"flex w-full shrink-0 flex-wrap items-center justify-end gap-1.5 sm:w-auto",onClick:e=>e.stopPropagation(),onKeyDown:e=>e.stopPropagation(),children:[(0,n.jsx)(e1,{kind:"start",targetPm2:i,busy:o,online:p,label:a("开始","Start"),className:"rounded-lg bg-emerald-500/20 text-emerald-100 ring-emerald-500/30",baseLock:!1,onRun:()=>void tj("start",i),notify:w,t:a,compact:!0}),(0,n.jsx)(e1,{kind:"stop",targetPm2:i,busy:o,online:p,label:a("停止","Stop"),className:"rounded-lg bg-rose-500/15 text-rose-100 ring-rose-500/25",baseLock:!1,onRun:()=>void tj("stop",i),notify:w,t:a,compact:!0}),(0,n.jsx)(e1,{kind:"restart",targetPm2:i,busy:o,online:p,label:a("重新开始","Restart"),className:"rounded-lg bg-amber-500/15 text-amber-100 ring-amber-500/25",baseLock:!1,onRun:()=>void tj("restart",i),notify:w,t:a,compact:!0}),g?(0,n.jsxs)("button",{type:"button",onClick:()=>{window.open((0,ex.p)(g.url),"_blank","noopener,noreferrer")},className:"inline-flex min-h-[2rem] items-center justify-center rounded-lg border border-emerald-500/25 bg-emerald-500/10 px-2.5 py-1.5 text-emerald-100 ring-1 ring-emerald-500/20 transition hover:bg-emerald-500/20",title:"".concat(a("打开该线路 Neko 工作室","Open this lane's Neko studio")," \xb7 ").concat(g.label).concat(g.port?" :".concat(g.port):""),"aria-label":"".concat(a("打开该线路 Neko 工作室","Open this lane's Neko studio")," \xb7 ").concat(g.label),children:[(0,n.jsx)("span",{className:"sr-only",children:a("打开该线路 Neko 工作室","Open this lane's Neko studio")}),(0,n.jsx)("span",{"aria-hidden":!0,className:"text-sm leading-none",children:"\uD83D\uDC31"}),(0,n.jsx)(Z.Z,{className:"ml-1 h-3.5 w-3.5 shrink-0","aria-hidden":!0})]}):null]})]},e.id)})})]})})]}),"single"===C?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("YouTube 相关设置","YouTube settings")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:a("串流参数写进 youtube.ini,无需 Google 登录。","Stream settings go to youtube.ini — no Google login.")}),(0,n.jsxs)("div",{className:"mt-4 space-y-3",children:[(0,n.jsx)("label",{className:"block text-xs text-zinc-400",children:a("串流密钥","Stream key")}),(0,n.jsx)("input",{className:"w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm font-mono text-zinc-200",spellCheck:!1,autoComplete:"off",value:I.key,onChange:e=>D(t=>({...t,key:e.target.value})),placeholder:"xxxx-xxxx-xxxx-xxxx-xxxx"}),(0,n.jsxs)("div",{className:"grid gap-3 sm:grid-cols-3",children:[(0,n.jsxs)("label",{className:"flex flex-col gap-1 text-xs text-zinc-400",children:["RTMPS",(0,n.jsxs)("select",{className:"rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-sm text-white",value:I.rtmps?"1":"0",onChange:e=>D(t=>({...t,rtmps:"1"===e.target.value})),children:[(0,n.jsx)("option",{value:"1",children:a("是(默认)","Yes")}),(0,n.jsx)("option",{value:"0",children:a("否 → RTMP","No")})]})]}),(0,n.jsxs)("label",{className:"flex flex-col gap-1 text-xs text-zinc-400",children:[a("比特率 kbps","Bitrate kbps"),(0,n.jsx)("input",{className:"rounded-lg border border-white/10 bg-black/40 px-3 py-2 font-mono text-sm",value:I.bitrate,onChange:e=>D(t=>({...t,bitrate:e.target.value})),placeholder:"4000"})]}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center gap-2 pt-6 text-xs text-zinc-300",children:[(0,n.jsx)("input",{type:"checkbox",className:"rounded border-white/20 bg-black/40",checked:I.fastAudio,onChange:e=>D(t=>({...t,fastAudio:e.target.checked}))}),"fast_audio(",a("轻量音频","lighter audio"),")"]})]})]}),(0,n.jsxs)("div",{className:"mt-4 flex flex-wrap gap-2",children:[(0,n.jsxs)("button",{type:"button",disabled:tk,onClick:()=>void tn(),className:"inline-flex items-center gap-2 rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-200",children:[(0,n.jsx)(y.Z,{className:"h-3.5 w-3.5 ".concat(H?"animate-spin":"")}),a("重新读取","Reload")]}),(0,n.jsxs)("button",{type:"button",disabled:tk,onClick:()=>void ta(),className:"inline-flex items-center gap-2 rounded-xl bg-violet-500/25 px-4 py-2 text-sm font-medium text-violet-100 ring-1 ring-violet-500/35",children:[H?(0,n.jsx)(v.Z,{className:"h-4 w-4 animate-spin"}):null,a("保存 youtube.ini","Save youtube.ini")]}),(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void to(),className:"rounded-xl border border-cyan-500/20 bg-cyan-500/10 px-4 py-2 text-sm text-cyan-100",children:a("平衡预设","Balanced preset")}),(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>{D(ep(U)),O(a("已从下方原文同步到表单","Synced from raw"))},className:"rounded-xl border border-white/10 px-4 py-2 text-sm text-zinc-400",children:a("从原文同步表单","Parse raw")})]}),(0,n.jsxs)("details",{className:"mt-4 rounded-xl border border-white/5 bg-black/20 p-3",children:[(0,n.jsx)("summary",{className:"cursor-pointer text-xs text-zinc-500",children:a("高级:youtube.ini 原文","Raw youtube.ini")}),(0,n.jsx)("textarea",{className:"mt-2 h-36 w-full resize-y rounded-lg border border-white/10 bg-black/50 p-3 font-mono text-[11px] text-zinc-400",value:U,onChange:e=>E(e.target.value),spellCheck:!1}),(0,n.jsx)("button",{type:"button",disabled:tk,className:"mt-2 rounded-lg bg-cyan-500/15 px-3 py-1.5 text-xs text-cyan-200",onClick:()=>void tr(U),children:a("保存原文","Save raw")})]}),A?(0,n.jsx)("p",{className:"mt-2 font-mono text-xs text-zinc-500",children:A}):null]}):(0,n.jsxs)("div",{className:"space-y-6",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsxs)("h3",{className:"text-sm font-semibold text-white",children:[a("当前线路","Current lane"),e2?(0,n.jsxs)("span",{className:"ml-2 font-normal text-zinc-400",children:["\xb7 ",e2.name]}):null,te?(0,n.jsx)("span",{className:"ml-2 rounded-md bg-amber-500/15 px-2 py-0.5 text-[10px] font-medium text-amber-100 ring-1 ring-amber-500/25",children:a("有未保存修改","Unsaved")}):null]}),e2?(0,n.jsxs)("p",{className:"mt-0.5 font-mono text-[11px] text-zinc-500",children:["PM2: ",e6,e9?" → ".concat(e8):""," \xb7 ","key ",tc||"—"]}):null]}),(0,n.jsxs)("button",{type:"button",disabled:tk,className:"inline-flex items-center gap-1 rounded-lg bg-violet-500/20 px-3 py-1.5 text-xs text-violet-100 ring-1 ring-violet-500/30",onClick:()=>{let e=eB(),t={id:e,name:"".concat(a("线路","Ch")," ").concat(P.length+1),streamKey:"",urlLines:"",pm2Name:eK(e),notes:""};et(s=>({...s,[e]:eq(t)})),e5([...P,t]),T(e),ey.current=eE(t),u(ey.current),ek("")},children:[(0,n.jsx)(e_.Z,{className:"h-3.5 w-3.5"}),a("新增线路","Add lane")]})]}),e2?(0,n.jsxs)("div",{className:"mt-4 space-y-3 border-t border-white/5 pt-4",children:[(0,n.jsx)("input",{className:"w-full rounded-xl border border-white/10 bg-black/40 px-3 py-2 text-sm",value:null!==(s=null==e3?void 0:e3.name)&&void 0!==s?s:"",onChange:e=>e4("name",e.target.value),placeholder:a("线路名称","Lane name")}),(0,n.jsx)("label",{className:"block text-xs text-zinc-500",children:a("串流密钥","Stream key")}),(0,n.jsx)("input",{className:"w-full rounded-xl border border-white/10 bg-black/40 px-3 py-2 font-mono text-sm",spellCheck:!1,value:null!==(l=null==e3?void 0:e3.streamKey)&&void 0!==l?l:"",onChange:e=>e4("streamKey",e.target.value),placeholder:"xxxx-xxxx… / rtmp(s)://…"}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void ti(),className:"rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-100",children:es?a("保存中...","Saving..."):a("保存线路设置","Save lane")}),(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void tm(),className:"rounded-xl bg-violet-500/25 px-4 py-2 text-sm font-medium text-violet-100 ring-1 ring-violet-500/35",children:a("写入 youtube.ini","Write youtube.ini")})]}),e7.ok?null:(0,n.jsx)("p",{className:"text-xs text-rose-300",children:e7.message}),(0,n.jsxs)("details",{className:"rounded-xl border border-white/5 bg-black/20 p-3",children:[(0,n.jsx)("summary",{className:"cursor-pointer text-xs text-zinc-500",children:a("高级:进程名","Advanced: process name")}),(0,n.jsx)("input",{className:"mt-2 w-full rounded-lg border border-white/10 bg-black/40 px-3 py-2 font-mono text-xs",value:null!==(i=null==e3?void 0:e3.pm2Name)&&void 0!==i?i:eK(e2.id),onChange:e=>e4("pm2Name",e.target.value),spellCheck:!1,placeholder:"youtube2__…"}),(0,n.jsxs)("p",{className:"mt-2 font-mono text-[11px] text-zinc-500",children:[a("实际生效","Effective"),": ",e8||"—"]}),e7.message&&!e7.ok?(0,n.jsx)("p",{className:"mt-2 text-[11px] text-rose-300",children:e7.message}):null]}),(0,n.jsx)("textarea",{className:"h-16 w-full resize-y rounded-xl border border-white/10 bg-black/40 p-3 text-xs text-zinc-300",value:null!==(r=null==e3?void 0:e3.notes)&&void 0!==r?r:"",onChange:e=>e4("notes",e.target.value),placeholder:a("备注(可选)","Notes (optional)")}),el?(0,n.jsx)("p",{className:"text-xs text-zinc-400",children:el}):null,(0,n.jsxs)("button",{type:"button",disabled:tk||P.length<2,className:"inline-flex items-center gap-1 text-xs text-rose-300 hover:text-rose-200 disabled:opacity-30",onClick:()=>{var e;let t=P.filter(e=>e.id!==e2.id);et(e=>{let t={...e};return delete t[e2.id],t}),e5(t),T((null===(e=t[0])||void 0===e?void 0:e.id)||"")},children:[(0,n.jsx)(ed.Z,{className:"h-3.5 w-3.5"}),a("删除此线路","Delete lane")]})]}):null]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("直播地址列表","URL list")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:a("每条线路独立写入自己的 URL_config..ini,不再复用或回填所谓“全局地址”。","Each lane writes to its own URL_config..ini with no shared global URL draft.")}),(0,n.jsx)("p",{className:"mt-1 font-mono text-[10px] text-zinc-600",children:x?eb(x):"URL_config.ini"}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2 text-[11px]",children:[(0,n.jsxs)("span",{className:"rounded-full border border-cyan-500/20 bg-cyan-500/10 px-2.5 py-1 text-cyan-100",children:[a("有效地址","Valid URLs"),": ",tp]}),(0,n.jsxs)("span",{className:"rounded-full border border-violet-500/20 bg-violet-500/10 px-2.5 py-1 text-violet-100",children:["Douyin: ",tb]})]}),tS,$?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:$}):null,(0,n.jsx)("textarea",{className:"mt-4 min-h-[160px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300",value:F,onChange:e=>{eo.current=!0,ek(e.target.value)},spellCheck:!1,placeholder:"https://live.douyin.com/..."}),(0,n.jsx)("div",{className:"mt-3 flex flex-wrap gap-2",children:(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void td(),className:"rounded-xl bg-cyan-500/20 px-4 py-2 text-sm text-cyan-100 ring-1 ring-cyan-500/30",children:a("保存地址","Save URLs")})})]})]}),"single"===C?(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:a("直播地址列表 \xb7 URL_config.ini","URL_config.ini")}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500",children:a("一行一个地址;可自动刷新或手动重新读取。","One URL per line; auto-refresh or reload.")}),(0,n.jsxs)("div",{className:"mt-3 flex flex-wrap gap-2 text-[11px]",children:[(0,n.jsxs)("span",{className:"rounded-full border border-cyan-500/20 bg-cyan-500/10 px-2.5 py-1 text-cyan-100",children:[a("有效地址","Valid URLs"),": ",tp]}),(0,n.jsxs)("span",{className:"rounded-full border border-violet-500/20 bg-violet-500/10 px-2.5 py-1 text-violet-100",children:["Douyin: ",tb]})]}),tS,$?(0,n.jsx)("p",{className:"mt-2 text-xs text-zinc-500",children:$}):null,(0,n.jsx)("textarea",{className:"mt-4 min-h-[200px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300",value:m,onChange:e=>{eo.current=!0,ej(e.target.value)},spellCheck:!1}),(0,n.jsx)("button",{type:"button",disabled:tk,onClick:()=>void tx(),className:"mt-3 rounded-xl bg-cyan-500/20 px-4 py-2 text-sm text-cyan-100 ring-1 ring-cyan-500/30",children:a("保存 URL 配置","Save URL config")})]}):null,(0,n.jsx)(ev,{t:a,currentProc:x,fetchJson:g,urlListText:"single"===C?m:F,keySuffixUi:tc,showKeyRow:!0,pollMs:800,refreshToken:er})]})}var e2=s(257);let e3=()=>void 0!==e2&&e2.env.NEXT_PUBLIC_API_URL||"";function e4(e){if(null==e||!Number.isFinite(e))return"—";if(0===e)return"0 B";let t=["B","KB","MB","GB","TB"],s=e,n=0;for(;s>=1024&&n=10||0===n?0:1)," ").concat(t[n])}function e6(e){let t=e4(e);return"—"===t?t:"".concat(t,"/s")}function e8(e){return"online"===e||"running"===e?"bg-emerald-500/15 text-emerald-300 ring-1 ring-emerald-500/30":"configured"===e?"bg-sky-500/15 text-sky-200 ring-1 ring-sky-500/25":"skipped"===e?"bg-slate-500/15 text-slate-300 ring-1 ring-slate-500/30":"stopped"===e||"not_found"===e?"bg-zinc-500/15 text-zinc-400 ring-1 ring-zinc-500/25":"error"===e?"bg-rose-500/15 text-rose-300 ring-1 ring-rose-500/35":"bg-violet-500/15 text-violet-200 ring-1 ring-violet-500/30"}function e9(e,t){let s=(e||"").trim().toLowerCase();return"online"===s||"running"===s?t("运行中","Running"):"configured"===s?t("已配置","Configured"):"not_found"===s?t("未注册","Unregistered"):"stopped"===s?t("已停止","Stopped"):"error"===s?t("异常","Error"):e||"—"}function e7(){var e,t,s,L,M,T,U,E,I,D,A,Z,O,H,B,K,F,W,J,G,V,q,X,$,Q,ee,et,es,en,el,ei,ea,eo,ec,ed,eu,em,eh,ep,eb,eg,ef,ev,ey,ew,eN,ej,ek,eS,e_,eR,eP,eL,eM,eT,eU,eE,eI,eD;let eA=e3(),[eZ,eO]=(0,_.useState)("zh"),[eH,eB]=(0,_.useState)("dark"),[eK,eF]=(0,_.useState)("dashboard"),[eW,eY]=(0,_.useState)(!1),[eJ,eG]=(0,_.useState)(null),[eV,eq]=(0,_.useState)(null),[eX,e$]=(0,_.useState)(!0),[eQ,e0]=(0,_.useState)(null),[e1,e2]=(0,_.useState)(null),[e7,te]=(0,_.useState)(null),[tt,ts]=(0,_.useState)(!0),[tn,tl]=(0,_.useState)([]),[ti,tr]=(0,_.useState)([]),[ta,to]=(0,_.useState)(""),[tc,td]=(0,_.useState)(""),[tx,tu]=(0,_.useState)("/sdcard/app.apk"),[tm,th]=(0,_.useState)(""),[tp,tb]=(0,_.useState)(null),[tg,tf]=(0,_.useState)(null),[tv,ty]=(0,_.useState)(!0),[tw,tN]=(0,_.useState)(!0),tj=(0,_.useRef)(null),tk=(0,_.useRef)(null),tz=(0,_.useRef)(ta),tS=(0,_.useRef)(0),t_=(0,_.useRef)(null),tC=(0,_.useCallback)((e,t)=>"zh"===eZ?e:t,[eZ]),tR=(0,_.useCallback)(e=>{e2(e),null!=t_.current&&window.clearTimeout(t_.current),t_.current=window.setTimeout(()=>{e2(null),t_.current=null},2800)},[]),tP=(0,_.useCallback)(async(e,t)=>(0,Y.N)("".concat(eA).concat(e),t),[eA]),tL=(0,_.useCallback)(async()=>{if(tj.current)return tj.current;let e=(async()=>{try{var e;let[t,s]=await Promise.allSettled([tP("/hub/dashboard"),tP("/deploy/check")]);if("fulfilled"!==t.status)throw t.reason;let n=t.value;eG(n),eq(null),te(Date.now()),"fulfilled"===s.status?tf(s.value):tf(null);let l=(null===(e=n.android)||void 0===e?void 0:e.devices)||[];if(l.length&&!tm){let e=l.find(e=>"device"===(e.state||"").toLowerCase());th((null!=e?e:l[0]).serial)}}catch(e){eq(e.message),tf(null)}finally{e$(!1),tj.current=null}})();return tj.current=e,e},[tm,tP]),tM=(0,_.useMemo)(()=>{let e=new URLSearchParams({light:"1"});return"live_youtube"===eK?e.set("family","youtube"):"live_tiktok"===eK&&e.set("family","tiktok"),"/process_monitor?".concat(e.toString())},[eK]),tT=(0,_.useCallback)(async()=>{if(tk.current)return tk.current;let e=(async()=>{try{let e=(await tP(tM)).entries||[];tr(e),tl(e.map(e=>({pm2:e.pm2,script:e.script,label:e.label}))),te(Date.now()),to(t=>!e.length||t&&e.some(e=>e.pm2===t)?t:e[0].pm2)}catch(e){}finally{tk.current=null}})();return tk.current=e,e},[tP,tM]);(0,_.useEffect)(()=>{let e=window.localStorage.getItem("live-hub-lang");("zh"===e||"en"===e)&&eO(e);let t=window.localStorage.getItem("live-hub-theme");("light"===t||"dark"===t)&&eB(t)},[]),(0,_.useEffect)(()=>{window.localStorage.setItem("live-hub-lang",eZ)},[eZ]),(0,_.useEffect)(()=>{document.documentElement.setAttribute("data-theme",eH);try{window.localStorage.setItem("live-hub-theme",eH)}catch(e){}},[eH]),(0,_.useEffect)(()=>{let e=()=>ts("visible"===document.visibilityState);return e(),document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[]),(0,_.useEffect)(()=>{if(!eW)return;let e=e=>{"Escape"===e.key&&eY(!1)};window.addEventListener("keydown",e);let t=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{window.removeEventListener("keydown",e),document.body.style.overflow=t}},[eW]),(0,_.useEffect)(()=>()=>{null!=t_.current&&window.clearTimeout(t_.current)},[]),(0,_.useEffect)(()=>{try{"0"===localStorage.getItem("livehub.autorefresh")&&ty(!1),"0"===localStorage.getItem("livehub.showStreamProbes")&&tN(!1)}catch(e){}},[]),(0,_.useEffect)(()=>{tL()},[tL]),(0,_.useEffect)(()=>{tT()},[tT]),(0,_.useEffect)(()=>{if(!tv||!tt||"live_youtube"===eK||"live_tiktok"===eK)return;let e=window.setInterval(()=>{tL()},1e4);return()=>clearInterval(e)},[tv,tt,tL,eK]),(0,_.useEffect)(()=>{if(!tv||!tt)return;let e=window.setInterval(()=>{tT()},"live_youtube"===eK||"live_tiktok"===eK?700:4e3);return()=>clearInterval(e)},[tv,tt,tT,eK]),(0,_.useEffect)(()=>{tz.current=ta},[ta]),(0,_.useEffect)(()=>{ta&&"live_youtube"===eK&&(async()=>{let e=tz.current.trim(),t=++tS.current;try{let s=new URLSearchParams({process:e,_ts:String(Date.now())}),n=await tP("/get_url_config?".concat(s));if(t!==tS.current||e!==tz.current.trim())return;td(n.content||"")}catch(e){}})()},[ta,tP,eK]),(0,_.useEffect)(()=>{"settings"===eK&&(async()=>{try{let e=await tP("/hub/config");tb(e)}catch(e){tb(null)}})()},[tP,eK]);let tU=(0,_.useMemo)(()=>{var e;let t=(null==eJ?void 0:null===(e=eJ.stack)||void 0===e?void 0:e.quick_links)||{},s={};for(let[e,n]of Object.entries(t))/^https?:\/\//i.test(n)?s[e]=(0,ex.p)(n):s[e]=n;return s},[null==eJ?void 0:null===(e=eJ.stack)||void 0===e?void 0:e.quick_links]),tE=(0,_.useMemo)(()=>(0,eC.O0)(tU),[tU]),tI=(0,_.useMemo)(()=>(0,eC.Tc)(tE),[tE]),tD=async(e,t)=>{e0("svc:".concat(e));try{let s=await tP("/service_action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({service:e,action:t})});"error"===s.status?tR(s.detail||s.message||tC("操作失败","Action failed")):tR(s.message||"OK"),await tL()}catch(e){tR(e.message)}finally{e0(null)}},tA=async(e,t)=>{let s=(null!=t?t:ta).trim();if(s){e0("proc:".concat(e,":").concat(s));try{let t=await tP("/".concat(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({process:s})});tR(String(t.output||t.message||"OK")),await tT(),"live_youtube"===eK||"live_tiktok"===eK?tL():await tL()}catch(e){tR(e.message)}finally{e0(null)}}},tZ=async(e,t)=>{let s=(null!=t?t:ta).trim();if(!s)return;let n=null!=e?e:tc,l=++tS.current;e0("save:url");try{let e=new URLSearchParams({process:s});await tP("/save_url_config?".concat(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:n})}),l===tS.current&&s===tz.current.trim()&&td(n),tR(tC("URL 配置已保存","URL config saved"))}catch(e){throw tR(e.message),e}finally{e0(null)}},tO=async function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!tm){tR(tC("请选择设备","Pick a device"));return}e0("adb:".concat(e));try{let s=await tP("/android/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,serial:tm,payload:t})});tR(s.message||"OK")}catch(e){tR(e.message)}finally{e0(null)}},tH=[{id:"dashboard",icon:r.Z,labelZh:"总览",labelEn:"Dashboard"},{id:"services",icon:a.Z,labelZh:"服务",labelEn:"Services"},{id:"live_youtube",icon:o.Z,labelZh:"YouTube 无人直播",labelEn:"YouTube unmanned"},{id:"live_tiktok",icon:c.Z,labelZh:"TikTok 无人直播",labelEn:"TikTok unmanned"},{id:"android",icon:d.Z,labelZh:"安卓",labelEn:"Android"},{id:"network",icon:x.Z,labelZh:"网络",labelEn:"Network"},{id:"settings",icon:u.Z,labelZh:"设置",labelEn:"Settings"}],tB=e=>{(async()=>{var t;if(null===(t=navigator.clipboard)||void 0===t?void 0:t.writeText){await navigator.clipboard.writeText(e);return}let s=document.createElement("textarea");s.value=e,s.readOnly=!0,s.style.position="fixed",s.style.opacity="0",document.body.appendChild(s),s.select(),document.execCommand("copy"),s.remove()})().then(()=>tR(tC("已复制","Copied")),()=>tR(tC("复制失败","Copy failed")))},tK=null!==(ev=null==eJ?void 0:null===(t=eJ.services)||void 0===t?void 0:t.filter(e=>e.running&&e.available).length)&&void 0!==ev?ev:0,tF=null!==(ey=null==eJ?void 0:null===(s=eJ.services)||void 0===s?void 0:s.length)&&void 0!==ey?ey:0,tW=e7?new Date(e7).toLocaleTimeString("zh"===eZ?"zh-CN":"en-US",{hour12:!1}):tC("未同步","Not synced"),tY=tt?tC("前台自动刷新","Auto refresh"):tC("后台已暂停刷新","Refresh paused in background");return(0,n.jsxs)("div",{className:"lp-root min-h-screen transition-colors duration-300 ".concat("light"===eH?"bg-slate-100 text-slate-900 selection:bg-violet-400/25":"bg-[#050508] text-zinc-100 selection:bg-violet-500/30"),children:[(0,n.jsx)("div",{className:"lp-noise pointer-events-none fixed inset-0 z-0 ".concat("light"===eH?"opacity-[0.06]":"opacity-[0.22]"),"aria-hidden":!0}),(0,n.jsx)("div",{className:"lp-aurora pointer-events-none fixed -left-1/4 top-0 h-[42rem] w-[42rem] rounded-full blur-[120px] ".concat("light"===eH?"bg-violet-400/15":"bg-violet-600/20"),"aria-hidden":!0}),(0,n.jsx)("div",{className:"lp-aurora2 pointer-events-none fixed bottom-0 right-0 h-[36rem] w-[36rem] rounded-full blur-[100px] ".concat("light"===eH?"bg-cyan-400/10":"bg-cyan-500/10"),"aria-hidden":!0}),e1?(0,n.jsx)(l.E.div,{initial:{opacity:0,y:16},animate:{opacity:1,y:0},role:"status","aria-live":"polite","aria-atomic":"true",className:"fixed bottom-6 left-1/2 z-[100] max-w-md -translate-x-1/2 rounded-2xl border border-white/10 bg-zinc-950/95 px-5 py-3 text-center text-sm text-zinc-100 shadow-2xl shadow-black/50 backdrop-blur-xl",children:e1}):null,(0,n.jsxs)("div",{className:"relative z-10 flex min-h-screen",children:[(0,n.jsxs)("aside",{className:"hidden w-64 shrink-0 flex-col border-r px-4 py-6 backdrop-blur-2xl lg:flex ".concat("light"===eH?"border-slate-200/90 bg-white/70":"border-white/[0.06] bg-zinc-950/40"),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 px-2",children:[(0,n.jsx)("div",{className:"flex h-9 w-9 items-center justify-center rounded-xl bg-gradient-to-br from-violet-500 to-cyan-400 shadow-lg shadow-violet-500/25",children:(0,n.jsx)(m.Z,{className:"h-4 w-4 text-white"})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-[0.2em] ".concat("light"===eH?"text-slate-500":"text-zinc-500"),children:"live.local"}),(0,n.jsx)("p",{className:"text-sm font-semibold ".concat("light"===eH?"text-slate-900":"text-white"),children:tC("无人直播系统","Unmanned Live System")})]})]}),(0,n.jsx)("nav",{className:"mt-10 flex flex-1 flex-col gap-1",children:tH.map(e=>{let t=e.icon,s=eK===e.id;return(0,n.jsxs)("button",{type:"button",onClick:()=>eF(e.id),"aria-current":s?"page":void 0,className:"flex items-center gap-3 rounded-xl px-3 py-2.5 text-left text-sm font-medium transition ".concat("light"===eH?s?"bg-violet-100/90 text-slate-900 shadow-inner shadow-violet-200/50":"text-slate-600 hover:bg-slate-200/60 hover:text-slate-900":s?"bg-white/[0.08] text-white shadow-inner shadow-white/5":"text-zinc-500 hover:bg-white/[0.04] hover:text-zinc-200"),children:[(0,n.jsx)(t,{className:"h-4 w-4 ".concat("light"===eH?s?"text-violet-600":"text-slate-400":s?"text-violet-300":"text-zinc-600")}),tC(e.labelZh,e.labelEn),s?(0,n.jsx)(h.Z,{className:"ml-auto h-4 w-4 ".concat("light"===eH?"text-slate-400":"text-zinc-600")}):null]},e.id)})})]}),(0,n.jsxs)("div",{className:"flex min-w-0 flex-1 flex-col",children:[(0,n.jsxs)("header",{className:"sticky top-0 z-20 flex items-center justify-between gap-3 border-b px-4 py-3 backdrop-blur-xl lg:px-8 ".concat("light"===eH?"border-slate-200/80 bg-white/75 text-slate-900":"border-white/[0.06] bg-zinc-950/70 text-white"),children:[(0,n.jsxs)("div",{className:"flex min-w-0 items-center gap-3",children:[(0,n.jsx)("button",{type:"button",className:"rounded-xl border p-2 lg:hidden ".concat("light"===eH?"border-slate-200 bg-white/80":"border-white/10 bg-white/5"),onClick:()=>eY(!0),"aria-label":"Menu",children:(0,n.jsx)(p.Z,{className:"h-5 w-5"})}),(0,n.jsxs)("div",{className:"min-w-0",children:[(0,n.jsx)("h1",{className:"truncate text-lg font-semibold tracking-tight lg:text-xl ".concat("light"===eH?"text-slate-900":"text-white"),children:tC((null===(L=tH.find(e=>e.id===eK))||void 0===L?void 0:L.labelZh)||"",(null===(M=tH.find(e=>e.id===eK))||void 0===M?void 0:M.labelEn)||"")}),(0,n.jsxs)("p",{className:"truncate text-xs ".concat("light"===eH?"text-slate-500":"text-zinc-500"),children:[(null==eJ?void 0:null===(T=eJ.stack)||void 0===T?void 0:T.mdns_host)||"live.local"," \xb7"," ","dark"===eH?tC("夜间","Dark mode"):tC("日间","Light mode")," \xb7 ",tY," \xb7"," ",tC("最后同步","Last sync")," ",tW]})]})]}),(0,n.jsxs)("div",{className:"flex shrink-0 items-center gap-1.5 sm:gap-2",children:[(0,n.jsx)("button",{type:"button",onClick:()=>eB(e=>"dark"===e?"light":"dark"),className:"rounded-xl border p-2 transition ".concat("light"===eH?"border-slate-200 bg-white text-amber-500 shadow-sm":"border-white/10 bg-white/[0.06] text-violet-200"),title:"dark"===eH?tC("切换到日间","Switch to light"):tC("切换到夜间","Switch to dark"),"aria-label":"dark"===eH?tC("日间模式","Light mode"):tC("夜间模式","Dark mode"),"aria-pressed":"light"===eH,children:"dark"===eH?(0,n.jsx)(b.Z,{className:"h-5 w-5",strokeWidth:2}):(0,n.jsx)(g.Z,{className:"h-5 w-5",strokeWidth:2})}),(0,n.jsxs)("button",{type:"button",onClick:()=>eO(e=>"zh"===e?"en":"zh"),className:"relative rounded-xl border p-2 transition ".concat("light"===eH?"border-slate-200 bg-white text-cyan-600 shadow-sm":"border-white/10 bg-white/[0.06] text-cyan-200"),title:"zh"===eZ?"English":"中文","aria-label":tC("切换语言","Toggle language"),"aria-pressed":"en"===eZ,children:[(0,n.jsx)(f.Z,{className:"h-5 w-5",strokeWidth:2}),(0,n.jsx)("span",{className:"absolute -bottom-0.5 -right-0.5 flex h-4 min-w-[1rem] items-center justify-center rounded px-0.5 text-[9px] font-bold leading-none ".concat("light"===eH?"bg-cyan-100 text-cyan-800":"bg-cyan-500/30 text-cyan-100"),children:"zh"===eZ?"中":"A"})]}),(0,n.jsxs)("button",{type:"button",disabled:!!eQ,onClick:()=>void Promise.all([tL(),tT()]),className:"flex items-center gap-2 rounded-xl border px-3 py-2 text-xs font-medium transition disabled:opacity-40 ".concat("light"===eH?"border-slate-200 bg-white text-slate-700 hover:bg-slate-50":"border-white/10 bg-white/[0.04] text-zinc-300 hover:bg-white/[0.07]"),children:[eQ?(0,n.jsx)(v.Z,{className:"h-3.5 w-3.5 animate-spin"}):(0,n.jsx)(y.Z,{className:"h-3.5 w-3.5"}),(0,n.jsx)("span",{className:"hidden sm:inline",children:tC("刷新","Refresh")})]})]})]}),(0,n.jsx)("main",{className:"flex-1 px-4 py-6 lg:px-8 lg:py-8",children:(0,n.jsx)(i.M,{mode:"wait",children:(0,n.jsxs)(l.E.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},exit:{opacity:0,y:-6},transition:{duration:.28,ease:[.22,1,.36,1]},children:["dashboard"===eK?(0,n.jsxs)("div",{className:"space-y-6",children:[eV?(0,n.jsxs)("div",{className:"rounded-2xl border border-rose-500/25 bg-rose-950/20 p-4 text-sm text-rose-200",children:[tC("无法加载仪表盘:","Dashboard error: "),eV]}):null,(0,n.jsx)(l.E.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:.02},className:"rounded-2xl border p-2 backdrop-blur-xl ".concat("light"===eH?"border-slate-200/90 bg-white/80 shadow-sm shadow-slate-200/30":"border-white/[0.07] bg-zinc-950/30"),children:(0,n.jsx)(R.Z,{snapshot:null!==(ew=null==eJ?void 0:eJ.snapshot)&&void 0!==ew?ew:null,theme:eH,tr:tC})}),(0,n.jsx)(l.E.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:.05},className:"rounded-2xl border p-3 shadow-lg ".concat("light"===eH?"border-fuchsia-200/80 bg-gradient-to-br from-fuchsia-50/90 via-white to-cyan-50/70 shadow-fuchsia-100/40":"border-fuchsia-500/20 bg-gradient-to-br from-fuchsia-500/10 via-zinc-950/60 to-cyan-500/10 shadow-fuchsia-900/10"),children:(0,n.jsx)(C,{tr:tC})}),(0,n.jsx)("div",{className:"grid gap-2 sm:grid-cols-2 xl:grid-cols-5",children:[{icon:w.Z,label:tC("CPU 1m","CPU 1m"),value:null!==(eN=null==eJ?void 0:null===(I=eJ.snapshot)||void 0===I?void 0:null===(E=I.cpu_load)||void 0===E?void 0:null===(U=E["1m"])||void 0===U?void 0:U.toFixed(2))&&void 0!==eN?eN:"—",sub:tC("负载均值","Load avg")},{icon:r.Z,label:tC("内存","Memory"),value:e4(null==eJ?void 0:null===(A=eJ.snapshot)||void 0===A?void 0:null===(D=A.memory)||void 0===D?void 0:D.available),sub:"/ ".concat(e4(null==eJ?void 0:null===(O=eJ.snapshot)||void 0===O?void 0:null===(Z=O.memory)||void 0===Z?void 0:Z.total))},{icon:N.Z,label:tC("磁盘可用","Disk free"),value:e4(null==eJ?void 0:null===(B=eJ.snapshot)||void 0===B?void 0:null===(H=B.disk)||void 0===H?void 0:H.free),sub:"/ ".concat(e4(null==eJ?void 0:null===(F=eJ.snapshot)||void 0===F?void 0:null===(K=F.disk)||void 0===K?void 0:K.total))},{icon:a.Z,label:tC("服务在线","Services up"),value:"".concat(tK,"/").concat(tF||"—"),sub:tC("基础服务层","Infra layer")},{icon:j.Z,label:tC("运行时间","Uptime"),value:function(e){if(null==e||!Number.isFinite(e))return"—";let t=Math.max(0,Math.floor(e)),s=Math.floor(t/86400),n=Math.floor(t%86400/3600),l=Math.floor(t%3600/60);return s>0?"".concat(s,"d ").concat(n,"h"):n>0?"".concat(n,"h ").concat(l,"m"):"".concat(l,"m")}(null==eJ?void 0:null===(W=eJ.snapshot)||void 0===W?void 0:W.uptime_seconds),sub:tC("自开机","Since boot")}].map((e,t)=>(0,n.jsxs)(l.E.div,{initial:{opacity:0,y:12},animate:{opacity:1,y:0},transition:{delay:.05*t,duration:.35,ease:[.22,1,.36,1]},whileHover:{y:-2},className:"group relative overflow-hidden rounded-xl border border-white/[0.07] bg-gradient-to-br from-white/[0.05] to-transparent p-3 shadow-lg shadow-black/20",children:[(0,n.jsx)("div",{className:"absolute -right-4 -top-4 h-16 w-16 rounded-full bg-violet-500/10 blur-xl transition group-hover:bg-violet-500/18"}),(0,n.jsx)(e.icon,{className:"h-4 w-4 text-violet-300/90"}),(0,n.jsx)("p",{className:"mt-2 text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:e.label}),(0,n.jsx)("p",{className:"mt-0.5 font-mono text-lg font-semibold leading-tight text-white",children:eX?"…":e.value}),(0,n.jsx)("p",{className:"mt-0.5 text-[10px] text-zinc-500",children:e.sub})]},e.label))}),(null==eJ?void 0:eJ.hardware)&&"object"==typeof eJ.hardware?(0,n.jsxs)("div",{className:"rounded-2xl border border-indigo-500/25 bg-gradient-to-br from-indigo-500/[0.1] via-zinc-950/70 to-violet-500/[0.08] p-6 shadow-2xl shadow-indigo-500/5",children:[(0,n.jsx)("h3",{className:"text-base font-semibold text-white",children:tC("系统硬件与软件能力","Hardware & software profile")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("来自 hardware_probe;用于直播/解码策略参考。","From hardware_probe; guides decode/streaming posture.")}),(0,n.jsxs)("div",{className:"mt-5 grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-indigo-300/90",children:tC("平台","Platform")}),(0,n.jsxs)("dl",{className:"space-y-2 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"arch"}),(0,n.jsx)("dd",{className:"text-right text-zinc-200",children:String(null!==(ej=eJ.hardware.arch)&&void 0!==ej?ej:"—")})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"kernel"}),(0,n.jsx)("dd",{className:"text-right text-zinc-200",children:String(null!==(eS=null!==(ek=eJ.hardware.kernel)&&void 0!==ek?ek:null===(J=eJ.stack)||void 0===J?void 0:J.kernel)&&void 0!==eS?eS:"—")})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"Python"}),(0,n.jsx)("dd",{className:"text-right text-zinc-200",children:String(null!==(e_=null===(G=eJ.stack)||void 0===G?void 0:G.python)&&void 0!==e_?e_:"—")})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"mDNS"}),(0,n.jsx)("dd",{className:"text-right text-cyan-200/90",children:null!==(eR=null===(V=eJ.stack)||void 0===V?void 0:V.mdns_host)&&void 0!==eR?eR:"—"})]}),(0,n.jsxs)("div",{className:"flex justify-between gap-2",children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"IP"}),(0,n.jsx)("dd",{className:"text-right text-zinc-300",children:((null===(q=eJ.stack)||void 0===q?void 0:q.ips)||[]).join(" \xb7 ")||"—"})]})]})]}),(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-fuchsia-300/90",children:"GPU / NPU"}),(()=>{let e=eJ.hardware.gpu,t=eJ.hardware.npu;return(0,n.jsxs)("dl",{className:"space-y-2 font-mono text-[11px] text-zinc-400",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"GPU"}),(0,n.jsxs)("dd",{className:"mt-0.5 text-zinc-200",children:[(null==e?void 0:e.present)?tC("已检测","present"):tC("未检测","absent"),(null==e?void 0:e.driver)?" \xb7 ".concat(e.driver):""]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"render"}),(0,n.jsx)("dd",{className:"mt-0.5 break-all text-zinc-500",children:((null==e?void 0:e.render_nodes)||[]).join(", ")||"—"})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("dt",{className:"text-zinc-600",children:"NPU"}),(0,n.jsx)("dd",{className:"mt-0.5 break-all text-zinc-500",children:(null==t?void 0:t.present)?(t.devices||[]).join(", "):tC("—","—")})]})]})})()]}),(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-white/[0.06] bg-black/30 p-4 lg:col-span-2",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-emerald-300/90",children:"ffmpeg / 建议策略"}),(()=>{var e,t,s,l;let i=eJ.hardware.ffmpeg_hwaccels||[],r=eJ.hardware.recommendation;return(0,n.jsxs)("div",{className:"space-y-2 text-[11px] text-zinc-400",children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"hwaccels: "}),(0,n.jsx)("span",{className:"font-mono text-emerald-200/90",children:i.length?i.join(", "):"—"})]}),(0,n.jsxs)("div",{className:"grid gap-2 sm:grid-cols-2",children:[(0,n.jsxs)("p",{children:[(0,n.jsxs)("span",{className:"text-zinc-600",children:[tC("解码","Decoder"),": "]}),(0,n.jsx)("span",{className:"text-zinc-200",children:null!==(e=null==r?void 0:r.video_decoder)&&void 0!==e?e:"—"})]}),(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"HDMI: "}),(0,n.jsx)("span",{className:"text-zinc-200",children:null!==(t=null==r?void 0:r.hdmi_player)&&void 0!==t?t:"—"})]}),(0,n.jsxs)("p",{children:[(0,n.jsx)("span",{className:"text-zinc-600",children:"Browser: "}),(0,n.jsx)("span",{className:"text-zinc-200",children:null!==(s=null==r?void 0:r.browser_hwaccel)&&void 0!==s?s:"—"})]}),(0,n.jsxs)("p",{children:[(0,n.jsxs)("span",{className:"text-zinc-600",children:[tC("稳定模式","Stability"),": "]}),(0,n.jsx)("span",{className:"text-amber-200/90",children:null!==(l=null==r?void 0:r.stability_mode)&&void 0!==l?l:"—"})]})]}),((null==r?void 0:r.degradation_reasons)||[]).length?(0,n.jsx)("ul",{className:"mt-2 list-inside list-disc space-y-1 text-[10px] text-amber-200/80",children:((null==r?void 0:r.degradation_reasons)||[]).map(e=>(0,n.jsx)("li",{children:e},e))}):null]})})()]})]})]}):null,tg?(0,n.jsxs)("div",{className:"rounded-2xl border p-5 ".concat(tg.ready?"border-emerald-500/25 bg-gradient-to-br from-emerald-500/[0.08] via-zinc-950/50 to-cyan-500/[0.05]":"border-amber-500/30 bg-gradient-to-br from-amber-500/[0.1] via-zinc-950/55 to-rose-500/[0.05]"),children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("安装验收","Deployment health")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("一键脚本完成后,本机 API、局域网入口、反向代理与 mDNS 的可用性检查。","Post-install checks for loopback API, LAN access, reverse proxy, and mDNS.")})]}),(0,n.jsx)("span",{className:"rounded-full px-3 py-1 text-[10px] font-semibold ".concat(tg.ready?"bg-emerald-500/20 text-emerald-100 ring-1 ring-emerald-500/30":"bg-amber-500/20 text-amber-100 ring-1 ring-amber-500/30"),children:tg.ready?tC("可交付","Ready"):tC("需处理","Needs attention")})]}),(0,n.jsxs)("div",{className:"mt-4 grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:tC("验收摘要","Acceptance summary")}),(0,n.jsxs)("p",{className:"mt-2 font-mono text-sm text-white",children:[null!==(eP=tg.pass_count)&&void 0!==eP?eP:0,"/",null!==(eL=tg.total_count)&&void 0!==eL?eL:0,(0,n.jsx)("span",{className:"ml-2 text-[11px] text-zinc-500",children:tC("已通过","checks passed")})]}),(0,n.jsxs)("p",{className:"mt-1 text-[11px] text-zinc-500",children:[tC("必需项","Required"),": ",null!==(eM=tg.required_total)&&void 0!==eM?eM:0," \xb7 mDNS"," ",tg.mdns_enabled?tC("已启用","enabled"):tC("已关闭","disabled")," \xb7 edge"," ",tg.live_edge_enabled?tC("已启用","enabled"):tC("已关闭","disabled")]}),(0,n.jsx)("div",{className:"mt-3 flex flex-wrap gap-2",children:Object.entries(tg.urls||{}).filter(e=>{let[,t]=e;return!!t}).slice(0,4).map(e=>{let[t,s]=e;return(0,n.jsx)("a",{href:(0,ex.p)(s),target:"_blank",rel:"noreferrer",className:"rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-[11px] text-zinc-200 ring-1 ring-white/10",children:t},t)})})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/30 p-4",children:[(0,n.jsx)("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:(null===(X=tg.failing_checks)||void 0===X?void 0:X.length)?tC("失败项","Failing checks"):tC("当前状态","Current state")}),(null===($=tg.failing_checks)||void 0===$?void 0:$.length)?(0,n.jsx)("ul",{className:"mt-2 space-y-2 text-[11px] text-zinc-300",children:tg.failing_checks.slice(0,4).map(e=>(0,n.jsxs)("li",{className:"rounded-lg border border-amber-500/20 bg-amber-500/10 px-3 py-2",children:[(0,n.jsx)("span",{className:"font-semibold text-amber-100",children:e.label}),(0,n.jsx)("span",{className:"ml-2 text-zinc-400",children:e.detail||"—"})]},e.id))}):(0,n.jsx)("p",{className:"mt-2 text-[11px] text-emerald-200/90",children:tC("必需检查已全部通过,可直接用浏览器面板交付。","All required checks pass; browser control plane is ready.")}),(tg.hints||[]).length?(0,n.jsx)("ul",{className:"mt-3 list-inside list-disc space-y-1 text-[10px] text-zinc-400",children:(tg.hints||[]).slice(0,3).map(e=>(0,n.jsx)("li",{children:e},e))}):null]})]})]}):null,(null==eJ?void 0:null===(Q=eJ.stack)||void 0===Q?void 0:Q.neko_login)?(0,n.jsxs)("div",{className:"rounded-2xl border border-fuchsia-500/25 bg-gradient-to-r from-fuchsia-500/[0.08] to-violet-500/[0.06] p-5",children:[(0,n.jsxs)("h3",{className:"text-sm font-semibold text-white",children:["Neko ",tC("登录","sign-in")]}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:eJ.stack.neko_login.note_zh||tC(tI?"Neko Chromium ".concat(tI," 使用下列账号策略。"):"Neko Chromium 多实例使用下列账号策略。",tI?"Neko Chromium ".concat(tI," uses the policy below."):"Neko Chromium instances use the policy below.")}),(0,n.jsx)("p",{className:"mt-2 text-[11px] text-amber-200/85",children:tC("重要:两栏分开填——昵称随意,密码必须是环境变量里的口令(默认 12345678)。用错密码会像一直加载;勿把「用户名/密码」写在一行。","Use two fields: display name is free-form; password must match NEKO_* (default 12345678). Wrong password looks like infinite loading.")}),tE.length?(0,n.jsx)("div",{className:"mt-4 flex flex-wrap gap-2",children:tE.map(e=>(0,n.jsxs)("a",{href:e.url,target:"_blank",rel:"noreferrer",className:"rounded-lg border border-fuchsia-400/20 bg-black/25 px-3 py-2 text-[11px] text-fuchsia-100 ring-1 ring-fuchsia-400/20",children:[e.label,e.port?" :".concat(e.port):""]},e.key))}):null,(0,n.jsxs)("div",{className:"mt-4 grid gap-3 sm:grid-cols-2 font-mono text-sm",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/40 px-4 py-3",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase text-zinc-500",children:tC("昵称示例","Display Name Example")}),(0,n.jsx)("p",{className:"mt-1 text-fuchsia-200",children:null!==(eT=eJ.stack.neko_login.user_login)&&void 0!==eT?eT:"live"}),(0,n.jsx)("p",{className:"mt-2 text-[10px] uppercase text-zinc-500",children:tC("连接口令","Access Password")}),(0,n.jsx)("p",{className:"mt-0.5 text-fuchsia-100",children:null!==(eU=eJ.stack.neko_login.user_password)&&void 0!==eU?eU:"—"})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/10 bg-black/40 px-4 py-3",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase text-zinc-500",children:tC("管理昵称示例","Admin Display Name Example")}),(0,n.jsx)("p",{className:"mt-1 text-violet-200",children:null!==(eE=eJ.stack.neko_login.admin_login)&&void 0!==eE?eE:"admin"}),(0,n.jsx)("p",{className:"mt-2 text-[10px] uppercase text-zinc-500",children:tC("管理口令","Admin Password")}),(0,n.jsx)("p",{className:"mt-0.5 text-violet-100",children:null!==(eI=eJ.stack.neko_login.admin_password)&&void 0!==eI?eI:"—"})]})]}),(0,n.jsx)("p",{className:"mt-3 text-[10px] text-zinc-600",children:tC("x86 默认使用 Neko 的 Chrome 镜像,ARM 默认使用 Chromium 镜像;默认保留管理员会话、开发者工具和 Tampermonkey 持久化。本栈未启用 Firefox 版 Neko。","x86 defaults to Neko’s Chrome image, ARM defaults to Chromium, and admin access, DevTools, plus persistent Tampermonkey stay enabled. This stack does not use Firefox Neko.")})]}):null,(null==eJ?void 0:null===(et=eJ.network)||void 0===et?void 0:null===(ee=et.interfaces)||void 0===ee?void 0:ee.length)?(0,n.jsxs)("div",{className:"rounded-2xl border border-cyan-500/15 bg-gradient-to-br from-cyan-500/[0.07] to-transparent p-5",children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold text-white",children:[(0,n.jsx)(k.Z,{className:"h-4 w-4 text-cyan-300"}),tC("网络带宽 / 流量","Network bandwidth / traffic")]}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("实时速率由总览自动刷新间隔计算;累计值来自系统网卡计数器。","Live rates are calculated from dashboard refresh deltas; totals come from kernel counters.")}),(0,n.jsxs)("div",{className:"mt-4 grid gap-3 sm:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/25 px-4 py-3 font-mono text-[11px]",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase tracking-[0.08em] text-cyan-300/70",children:tC("实时下行","Live down")}),(0,n.jsx)("p",{className:"mt-1 text-lg font-semibold text-cyan-100",children:e6(eJ.network.total_rx_bps)}),(0,n.jsxs)("p",{className:"mt-1 text-zinc-500",children:[tC("累计","Total"),": ",e4(eJ.network.total_rx_bytes)]})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/25 px-4 py-3 font-mono text-[11px]",children:[(0,n.jsx)("p",{className:"text-[10px] uppercase tracking-[0.08em] text-cyan-300/70",children:tC("实时上行","Live up")}),(0,n.jsx)("p",{className:"mt-1 text-lg font-semibold text-cyan-100",children:e6(eJ.network.total_tx_bps)}),(0,n.jsxs)("p",{className:"mt-1 text-zinc-500",children:[tC("累计","Total"),": ",e4(eJ.network.total_tx_bytes)]})]})]}),(0,n.jsx)("div",{className:"mt-4 grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:(eJ.network.interfaces||[]).slice(0,6).map(e=>{var t,s,l,i;return(0,n.jsxs)("div",{className:"rounded-xl border border-white/[0.06] bg-black/25 px-4 py-3 font-mono text-[11px]",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-cyan-200/90",children:e.name}),(0,n.jsxs)("p",{className:"mt-2 text-zinc-500",children:[tC("链路","Link"),": ",e.operstate||"unknown"," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",e.speed_mbps?"".concat(e.speed_mbps," Mbps"):tC("未知速率","unknown speed")]}),(0,n.jsxs)("p",{className:"mt-2 text-zinc-500",children:["↓ ",e6(e.rx_bps)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",e4(e.rx_bytes)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",null!==(l=null===(t=e.rx_packets)||void 0===t?void 0:t.toLocaleString())&&void 0!==l?l:"—"," pkt"]}),(0,n.jsxs)("p",{className:"mt-0.5 text-zinc-500",children:["↑ ",e6(e.tx_bps)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",e4(e.tx_bytes)," ",(0,n.jsx)("span",{className:"text-zinc-600",children:"\xb7"})," ",null!==(i=null===(s=e.tx_packets)||void 0===s?void 0:s.toLocaleString())&&void 0!==i?i:"—"," pkt"]})]},e.name)})})]}):null,(null==eJ?void 0:null===(en=eJ.live_events)||void 0===en?void 0:null===(es=en.pm2_tail)||void 0===es?void 0:es.length)||(null==eJ?void 0:null===(ei=eJ.live_events)||void 0===ei?void 0:null===(el=ei.process_digest)||void 0===el?void 0:el.length)?(0,n.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-2xl border border-amber-500/15 bg-zinc-950/40 p-5",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("直播 / PM2 事件","Live / PM2 feed")}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("PM2 合并日志尾部","PM2 merged log tail")}),(0,n.jsx)("pre",{className:"mt-3 max-h-48 overflow-auto whitespace-pre-wrap rounded-lg border border-white/[0.05] bg-black/40 p-3 font-mono text-[10px] leading-relaxed text-zinc-400",children:((null==eJ?void 0:null===(ea=eJ.live_events)||void 0===ea?void 0:ea.pm2_tail)||[]).join("\n")||tC("暂无 PM2 输出","No PM2 output")})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/15 bg-zinc-950/40 p-5",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("进程快照","Process digest")}),(0,n.jsx)("ul",{className:"mt-3 space-y-2",children:((null==eJ?void 0:null===(eo=eJ.live_events)||void 0===eo?void 0:eo.process_digest)||[]).map(e=>(0,n.jsxs)("li",{className:"flex items-center justify-between gap-2 rounded-lg border border-white/[0.05] bg-black/30 px-3 py-2 text-xs",children:[(0,n.jsx)("span",{className:"truncate text-zinc-300",children:e.label||e.pm2}),(0,n.jsx)("span",{className:"shrink-0 rounded-md px-2 py-0.5 text-[10px] font-medium ".concat(e8(e.status||"")),children:e9(e.status||"",tC)})]},e.pm2))})]})]}):null,(0,n.jsxs)("div",{className:"rounded-2xl border border-violet-500/20 bg-gradient-to-br from-violet-500/[0.12] via-zinc-950/50 to-fuchsia-500/[0.06] p-5 shadow-lg shadow-violet-500/5",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("h3",{className:"text-sm font-semibold text-white",children:tC("直播进程","Live processes")}),(0,n.jsx)("span",{className:"rounded-full bg-white/10 px-2 py-0.5 text-[10px] font-medium text-zinc-300",children:(null==eJ?void 0:null===(ec=eJ.live)||void 0===ec?void 0:ec.backend_mode)||"—"})]}),(0,n.jsxs)("ul",{className:"mt-4 space-y-2.5",children:[((null==eJ?void 0:null===(ed=eJ.live)||void 0===ed?void 0:ed.processes)||[]).slice(0,10).map(e=>(0,n.jsxs)("li",{className:"group flex items-center gap-3 rounded-xl border border-white/[0.08] bg-black/35 px-3 py-2.5 transition hover:border-violet-400/25 hover:bg-black/45",children:[(0,n.jsx)("div",{className:"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-violet-500/30 to-fuchsia-500/20 text-[10px] font-bold text-violet-100 ring-1 ring-white/10",children:"LIVE"}),(0,n.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,n.jsx)("p",{className:"truncate text-sm font-medium text-zinc-100",children:e.label||e.pm2}),(0,n.jsx)("p",{className:"truncate font-mono text-[10px] text-zinc-600",children:e.script||e.pm2})]}),(0,n.jsx)("span",{className:"shrink-0 rounded-lg px-2.5 py-1 text-[10px] font-semibold ".concat(e8(e.process_status||"")),children:e9(e.process_status||"",tC)})]},e.pm2)),(null==eJ?void 0:null===(em=eJ.live)||void 0===em?void 0:null===(eu=em.processes)||void 0===eu?void 0:eu.length)?null:(0,n.jsx)("li",{className:"rounded-xl border border-dashed border-white/10 py-8 text-center text-xs text-zinc-600",children:tC("暂无直播进程","No live processes")})]}),(0,n.jsxs)("div",{className:"mt-5 grid grid-cols-2 gap-2",children:[(0,n.jsx)("button",{type:"button",onClick:()=>eF("live_youtube"),className:"rounded-xl border border-violet-400/35 bg-violet-500/15 py-2.5 text-[11px] font-semibold text-violet-100 shadow-inner shadow-black/20 transition hover:bg-violet-500/25",children:"YouTube"}),(0,n.jsx)("button",{type:"button",onClick:()=>eF("live_tiktok"),className:"rounded-xl border border-cyan-400/35 bg-cyan-500/15 py-2.5 text-[11px] font-semibold text-cyan-100 shadow-inner shadow-black/20 transition hover:bg-cyan-500/25",children:"TikTok"})]})]}),(null==eJ?void 0:eJ.probes)&&tw?(0,n.jsxs)("div",{className:"grid gap-3 sm:grid-cols-2 lg:grid-cols-3",children:[eJ.probes.srs?(()=>{var e,t,s,l,i,r,a;let o=null===(e=eJ.probes)||void 0===e?void 0:e.srs,c=null==o?void 0:null===(t=o.tcp)||void 0===t?void 0:t.reachable,d=null==o?void 0:null===(s=o.tcp_api)||void 0===s?void 0:s.reachable,x=null==o?void 0:o.http_ui,u=null==o?void 0:o.http,m=null==o?void 0:o.api_port,h=null!==(i=null==o?void 0:o.api_ok)&&void 0!==i?i:(null==u?void 0:u.http_code)===200,p=null==x?void 0:x.http_code;return(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.07] bg-zinc-950/40 p-4 backdrop-blur-sm",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-white",children:"SRS"}),(0,n.jsx)("span",{className:"rounded-full px-2 py-0.5 text-[10px] font-semibold ".concat(h?"bg-emerald-500/20 text-emerald-200 ring-1 ring-emerald-500/30":"bg-rose-500/15 text-rose-200 ring-1 ring-rose-500/25"),children:h?tC("API 正常","API OK"):tC("API 异常","API down")})]}),(0,n.jsxs)("p",{className:"mt-1 font-mono text-[11px] text-zinc-500",children:[":",null!==(r=null==o?void 0:o.port)&&void 0!==r?r:"—"," / API :",null!=m?m:"—"," \xb7 TCP ",c?"OK":"—"," \xb7 API TCP"," ",d?"OK":"—"]}),(0,n.jsxs)("p",{className:"mt-1 font-mono text-[11px] text-zinc-500",children:["API HTTP ",null!==(a=null==u?void 0:u.http_code)&&void 0!==a?a:"—"," \xb7 ",tC("根路径","root")," ",null!=p?p:"—",404===p?tC("(无首页不影响推流)"," (no index is OK for streaming)"):null]}),(0,n.jsxs)("p",{className:"mt-1 text-[11px] text-zinc-500",children:[tC("延迟","RTT")," ",(null==u?void 0:u.latency_ms)!=null?"".concat(u.latency_ms," ms"):(null==o?void 0:null===(l=o.tcp)||void 0===l?void 0:l.latency_ms)!=null?"".concat(o.tcp.latency_ms," ms"):"—"]}),!h&&(null==u?void 0:u.error)?(0,n.jsx)("p",{className:"mt-1 line-clamp-2 text-[10px] text-amber-200/80",children:u.error}):null]})})():null,eJ.probes.neko?(()=>{var e,t,s,l,i,r,a;let o=null===(e=eJ.probes)||void 0===e?void 0:e.neko,c=null==o?void 0:null===(t=o.tcp)||void 0===t?void 0:t.reachable,d=null==o?void 0:o.http,x=(null==o?void 0:o.instances)||[],u=null!==(l=null==o?void 0:o.running_count)&&void 0!==l?l:x.filter(e=>{var t;return null===(t=e.tcp)||void 0===t?void 0:t.reachable}).length,m=null!==(i=null==o?void 0:o.required_count)&&void 0!==i?i:x.length;return(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.07] bg-zinc-950/40 p-4 backdrop-blur-sm",children:[(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("p",{className:"text-xs font-semibold text-white",children:"Neko Chromium"}),(0,n.jsxs)("span",{className:"rounded-full px-2 py-0.5 text-[10px] font-semibold ".concat(u>0?"bg-emerald-500/20 text-emerald-200 ring-1 ring-emerald-500/30":"bg-rose-500/15 text-rose-200 ring-1 ring-rose-500/25"),children:[u,"/",m||"—"," ",tC("在线","online")]})]}),(0,n.jsx)("p",{className:"mt-1 text-[11px] text-zinc-500",children:tC("Docker 内 Chromium(非 Chrome 品牌);arm64/x86 同一镜像。","Chromium in Docker (not Chrome branding); multi-arch.")}),(0,n.jsxs)("p",{className:"mt-2 font-mono text-[11px] text-zinc-500",children:[":",null!==(r=null==o?void 0:o.port)&&void 0!==r?r:"—"," \xb7 TCP ",c?"OK":"—"," \xb7 HTTP ",null!==(a=null==d?void 0:d.http_code)&&void 0!==a?a:"—"]}),(0,n.jsxs)("p",{className:"mt-1 text-[11px] text-zinc-500",children:[tC("延迟","RTT")," ",(null==d?void 0:d.latency_ms)!=null?"".concat(d.latency_ms," ms"):(null==o?void 0:null===(s=o.tcp)||void 0===s?void 0:s.latency_ms)!=null?"".concat(o.tcp.latency_ms," ms"):"—"]}),x.length?(0,n.jsx)("div",{className:"mt-3 space-y-2",children:x.map(e=>{var t,s,l,i,r,a,o;return(0,n.jsxs)("div",{className:"flex items-center justify-between gap-3 rounded-lg border border-white/[0.05] bg-black/25 px-3 py-2",children:[(0,n.jsxs)("div",{className:"min-w-0",children:[(0,n.jsxs)("p",{className:"text-[11px] font-semibold text-zinc-200",children:["Neko ",null!==(r=e.id)&&void 0!==r?r:"?"]}),(0,n.jsxs)("p",{className:"font-mono text-[10px] text-zinc-500",children:[":",null!==(a=e.port)&&void 0!==a?a:"—"," \xb7 TCP ",(null===(t=e.tcp)||void 0===t?void 0:t.reachable)?"OK":"—"," \xb7 HTTP"," ",null!==(o=null===(s=e.http)||void 0===s?void 0:s.http_code)&&void 0!==o?o:"—"]})]}),(0,n.jsx)("span",{className:"shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold ".concat((null===(l=e.tcp)||void 0===l?void 0:l.reachable)?"bg-emerald-500/15 text-emerald-200 ring-1 ring-emerald-500/25":"bg-zinc-500/15 text-zinc-400 ring-1 ring-zinc-500/25"),children:(null===(i=e.tcp)||void 0===i?void 0:i.reachable)?tC("运行中","Running"):tC("未连通","Offline")})]},"".concat(e.id,"-").concat(e.port))})}):null,!(null==d?void 0:d.reachable)&&(null==d?void 0:d.error)?(0,n.jsx)("p",{className:"mt-1 line-clamp-2 text-[10px] text-amber-200/80",children:d.error}):null]})})():null]}):null]}):null,"services"===eK?(0,n.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-3",children:[((null==eJ?void 0:eJ.services)||[]).map((e,t)=>(0,n.jsxs)(l.E.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},transition:{delay:.04*t},whileHover:{y:-2},className:"rounded-2xl border border-white/[0.07] bg-gradient-to-b from-white/[0.05] to-transparent p-5",children:[(0,n.jsxs)("div",{className:"flex items-start justify-between gap-2",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-semibold text-white",children:e.label}),(0,n.jsx)("p",{className:"mt-1 text-xs text-zinc-500 line-clamp-2",children:e.description})]}),(0,n.jsx)("span",{className:"shrink-0 rounded-full px-2.5 py-1 text-[10px] font-semibold ".concat(e8(e.running?"online":e.status)),children:e.running?tC("运行中","Running"):e.status})]}),e.detail?(0,n.jsx)("p",{className:"mt-2 text-[11px] leading-snug line-clamp-6 ".concat("skipped"===e.status?"text-slate-300/90":"text-amber-200/85"),children:e.detail}):null,"shellcrash"===e.service_id&&e.available&&!e.running?(0,n.jsx)("p",{className:"mt-2 text-[11px] text-zinc-500",children:tC("stopped 为常态:仅当需要透明代理 / 规则分流时再点 Start(或 systemctl enable --now shellcrash)。","Stopped is normal; Start only when you need the proxy (or enable shellcrash.service).")}):null,(0,n.jsxs)("div",{className:"mt-4 flex flex-wrap items-center gap-2",children:[e.url?(0,n.jsx)("a",{href:(0,ex.p)(e.url),target:"_blank",rel:"noreferrer",className:"rounded-lg bg-violet-500/15 px-3 py-1.5 text-xs font-medium text-violet-200 ring-1 ring-violet-500/25",children:tC("打开面板","Open panel")}):null,(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"start"),className:"rounded-lg bg-emerald-500/20 px-3 py-1.5 text-xs font-medium text-emerald-200 ring-1 ring-emerald-500/30 disabled:opacity-30",children:"Start"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"install"),className:"rounded-lg bg-sky-500/15 px-3 py-1.5 text-xs font-medium text-sky-200 ring-1 ring-sky-500/25 disabled:opacity-30",children:"Install"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"restart"),className:"rounded-lg bg-amber-500/15 px-3 py-1.5 text-xs font-medium text-amber-200 ring-1 ring-amber-500/25 disabled:opacity-30",children:"Restart"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"upgrade"),className:"rounded-lg bg-indigo-500/15 px-3 py-1.5 text-xs font-medium text-indigo-200 ring-1 ring-indigo-500/25 disabled:opacity-30",children:"Upgrade"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"stop"),className:"rounded-lg bg-rose-500/15 px-3 py-1.5 text-xs font-medium text-rose-200 ring-1 ring-rose-500/25 disabled:opacity-30",children:"Stop"}),(0,n.jsx)("button",{type:"button",disabled:!!eQ||!e.available||"android_gateway"===e.service_id&&"skipped"===e.status,title:"android_gateway"===e.service_id&&"skipped"===e.status?tC("单网口无需网关","Not needed on single NIC"):e.available?void 0:e.detail||tC("当前不可操作","Unavailable"),onClick:()=>void tD(e.service_id,"uninstall"),className:"rounded-lg bg-zinc-500/15 px-3 py-1.5 text-xs font-medium text-zinc-200 ring-1 ring-zinc-500/25 disabled:opacity-30",children:"Uninstall"})]})]},e.service_id)),(null==eJ?void 0:null===(eh=eJ.services)||void 0===eh?void 0:eh.length)?null:(0,n.jsx)("p",{className:"text-sm text-zinc-500",children:tC("暂无服务数据","No services")})]}):null,"live_youtube"===eK?(0,n.jsx)(e5,{t:tC,busy:eQ,entries:tn,currentProc:ta,setCurrentProc:to,urlConfig:tc,setUrlConfig:td,onRunProcess:(e,t)=>void tA(e,t),onSaveUrlConfig:(e,t)=>tZ(e,t),fetchJson:tP,liveProcesses:ti.length?ti:null!==(eD=null==eJ?void 0:null===(ep=eJ.live)||void 0===ep?void 0:ep.processes)&&void 0!==eD?eD:[],notify:tR,quickLinks:tU,onNavigate:e=>eF(e)}):null,"live_tiktok"===eK?(0,n.jsx)(ez,{t:tC,busy:!!eQ,entries:tn,currentProc:ta,setCurrentProc:to,urlConfig:tc,setUrlConfig:td,onRunProcess:e=>void tA(e),onSaveUrlConfig:e=>tZ(e),onReplayGoLive:async(e,t)=>{let s=t.replace(/[,,|]/g,"_");await tZ("原画,".concat(e,",主播: ").concat(s)),await tA("start")},onCopy:tB,fetchJson:tP,apiPrefix:eA,quickLinks:tU,hdmiStatus:null==eJ?void 0:eJ.hdmi,notify:tR,onNavigate:e=>eF(e)}):null,"android"===eK?(0,n.jsx)(er,{t:tC,notify:tR,fetchJson:tP,apiBase:eA,busy:eQ,androidSerial:tm,setAndroidSerial:th,devices:(null==eJ?void 0:null===(eb=eJ.android)||void 0===eb?void 0:eb.devices)||[],adbAvailable:!!(null==eJ?void 0:null===(eg=eJ.android)||void 0===eg?void 0:eg.adb_available),apkPath:tx,setApkPath:tu,onAndroidAction:(e,t)=>tO(e,null!=t?t:{}),onCopy:tB,onRefreshDevices:()=>void tL()}):null,"network"===eK?(0,n.jsxs)("div",{className:"mx-auto max-w-7xl space-y-6",children:[(0,n.jsxs)("div",{className:"rounded-2xl border p-6 ".concat("light"===eH?"border-violet-200/90 bg-gradient-to-br from-violet-50 via-white to-fuchsia-50/80":"border-violet-500/25 bg-gradient-to-br from-violet-500/10 via-zinc-950/40 to-fuchsia-500/5"),children:[(0,n.jsxs)("h3",{className:"flex items-center gap-2 text-sm font-semibold ".concat("light"===eH?"text-slate-900":"text-white"),children:[(0,n.jsx)(k.Z,{className:"h-4 w-4 ".concat("light"===eH?"text-violet-600":"text-violet-300")}),tC("ShellCrash 网络面板","ShellCrash panel")]}),(0,n.jsx)("p",{className:"mt-2 text-xs ".concat("light"===eH?"text-slate-600":"text-zinc-400"),children:tC("透明代理与规则分流直接在本页完成,无需跳转;流媒体与其它系统服务请在「服务」页管理。","Proxy rules and YAML editing are embedded here. Use Services for SRS/Neko/Chromium, etc.")}),(0,n.jsx)("div",{className:"mt-6 flex flex-col items-center gap-4 sm:flex-row sm:justify-center",children:[{tx:tC("互联网","Internet"),c:"from-cyan-400 to-blue-500"},{tx:"ShellCrash",c:"from-violet-500 to-fuchsia-500"},{tx:tC("本机 / 安卓","Host / Android"),c:"from-emerald-400 to-teal-500"}].map((e,t)=>(0,n.jsxs)("div",{className:"flex items-center gap-4",children:[(0,n.jsx)("div",{className:"flex h-16 w-28 items-center justify-center rounded-2xl bg-gradient-to-br ".concat(e.c," text-xs font-bold text-white shadow-lg"),children:e.tx}),t<2?(0,n.jsx)(h.Z,{className:"hidden h-5 w-5 sm:block ".concat("light"===eH?"text-slate-400":"text-zinc-600")}):null]},e.tx))})]}),(0,n.jsx)("div",{className:"overflow-hidden rounded-2xl border shadow-xl ".concat("light"===eH?"border-slate-200/90 bg-white shadow-slate-200/40":"border-white/[0.08] bg-zinc-950/50 shadow-black/30"),children:(0,n.jsx)("div",{className:"max-h-[min(78vh,56rem)] min-h-[22rem] overflow-y-auto overflow-x-hidden",children:(0,n.jsx)(P.d,{embeddedShellCrash:!0,portalLang:eZ})})})]}):null,"settings"===eK?(0,n.jsxs)("div",{className:"mx-auto max-w-lg space-y-6",children:[(0,n.jsx)("p",{className:"text-sm ".concat("light"===eH?"text-slate-600":"text-zinc-400"),children:tC("常用选项(本机偏好);完整文件与 JSON 编辑见下方链接。","Local preferences; full file/JSON editor via the link below.")}),(0,n.jsxs)("div",{className:"space-y-4 rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-5",children:[(0,n.jsxs)("label",{className:"flex cursor-pointer items-center justify-between gap-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("p",{className:"text-sm font-medium text-white",children:tC("总览自动刷新","Auto-refresh dashboard")}),(0,n.jsx)("p",{className:"text-[11px] text-zinc-500",children:"10s"})]}),(0,n.jsx)("input",{type:"checkbox",className:"h-5 w-5 accent-violet-500",checked:tv,onChange:e=>{let t=e.target.checked;ty(t);try{localStorage.setItem("livehub.autorefresh",t?"1":"0")}catch(e){}tR(t?tC("已开启刷新","Auto refresh on"):tC("已暂停刷新","Paused"))}})]}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-center justify-between gap-4 border-t border-white/[0.06] pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("p",{className:"text-sm font-medium text-white",children:tC("总览显示 SRS / Neko 探针","Show SRS/Neko probes")}),(0,n.jsx)("p",{className:"text-[11px] text-zinc-500",children:tC("关闭可精简首页","Hide stream probe cards")})]}),(0,n.jsx)("input",{type:"checkbox",className:"h-5 w-5 accent-violet-500",checked:tw,onChange:e=>{let t=e.target.checked;tN(t);try{localStorage.setItem("livehub.showStreamProbes",t?"1":"0")}catch(e){}}})]})]}),(0,n.jsxs)("div",{className:"rounded-2xl border border-white/[0.08] bg-zinc-950/40 p-5",children:[(0,n.jsx)("p",{className:"text-xs font-semibold uppercase tracking-wider text-zinc-500",children:tC("配置快照","Config snapshot")}),(0,n.jsx)("p",{className:"mt-2 font-mono text-[11px] text-zinc-400",children:String((null==tp?void 0:tp.config_root)||"—")}),(0,n.jsxs)("p",{className:"mt-3 text-sm text-zinc-300",children:[tC("主机名","Hostname"),":"," ",(0,n.jsx)("span",{className:"font-mono text-violet-200",children:(()=>{var e,t,s;let n=null==tp?void 0:tp.system;return(null==n?void 0:null===(t=n.identity)||void 0===t?void 0:null===(e=t.hostname_alias)||void 0===e?void 0:e.trim())||((null==eJ?void 0:null===(s=eJ.stack)||void 0===s?void 0:s.mdns_host)||"").replace(/\.local$/i,"")||"—"})()})]}),(0,n.jsx)("div",{className:"mt-4 flex flex-wrap gap-2",children:null==tp?void 0:null===(ef=tp.services)||void 0===ef?void 0:ef.slice(0,8).map(e=>(0,n.jsxs)("span",{className:"rounded-full px-2.5 py-1 text-[10px] font-medium ".concat(e.enabled?"bg-emerald-500/15 text-emerald-200 ring-1 ring-emerald-500/25":"bg-zinc-500/15 text-zinc-400"),children:[e.id," ",e.enabled?"ON":"off"]},e.id))})]}),(0,n.jsxs)("a",{href:"/console?tab=config",className:"inline-flex w-full items-center justify-center gap-2 rounded-xl border py-3 text-sm transition ".concat("light"===eH?"border-slate-200 bg-slate-50 text-violet-700 hover:bg-slate-100":"border-white/10 bg-white/[0.05] text-violet-200 hover:bg-white/[0.08]"),children:[tC("完整配置中心(文件 / JSON)","Full config center (files / JSON)"),(0,n.jsx)(z.Z,{className:"h-4 w-4"})]})]}):null]},eK)})})]})]}),(0,n.jsx)(i.M,{children:eW?(0,n.jsx)(l.E.div,{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},className:"fixed inset-0 z-50 bg-black/60 backdrop-blur-sm lg:hidden",onClick:()=>eY(!1),children:(0,n.jsxs)(l.E.aside,{initial:{x:-280},animate:{x:0},exit:{x:-280},transition:{type:"spring",damping:28,stiffness:320},className:"absolute left-0 top-0 h-full w-[min(88vw,280px)] border-r border-white/10 bg-zinc-950 p-4 shadow-2xl",onClick:e=>e.stopPropagation(),children:[(0,n.jsx)("div",{className:"flex justify-end",children:(0,n.jsx)("button",{type:"button",onClick:()=>eY(!1),className:"rounded-lg p-2",children:(0,n.jsx)(S.Z,{className:"h-5 w-5"})})}),(0,n.jsx)("nav",{className:"mt-4 flex flex-col gap-1",children:tH.map(e=>{let t=e.icon,s=eK===e.id;return(0,n.jsxs)("button",{type:"button",onClick:()=>{eF(e.id),eY(!1)},"aria-current":s?"page":void 0,className:"flex items-center gap-3 rounded-xl px-3 py-3 text-left text-sm transition ".concat(s?"bg-white/[0.08] text-white shadow-inner shadow-white/5":"text-zinc-300 hover:bg-white/[0.04]"),children:[(0,n.jsx)(t,{className:"h-4 w-4 ".concat(s?"text-violet-300":"text-violet-400")}),tC(e.labelZh,e.labelEn)]},e.id)})})]})}):null})]})}}},function(e){e.O(0,[500,719,246,971,117,744],function(){return e(e.s=4578)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/d2ypp2/web-console/out/android.html b/d2ypp2/web-console/out/android.html index 4b38612..82b61a8 100644 --- a/d2ypp2/web-console/out/android.html +++ b/d2ypp2/web-console/out/android.html @@ -1 +1 @@ -无人直播系统 · live.local
返回门户首页无人直播 · 本页需与 API 同域(推荐 live.local:8001)

控制平面 · ARM Linux 开发板

无人直播控制中心

ShellCrash 负责代理上网;本机 FFmpeg 处理推流或 HDMI;Neko(Docker Chromium)或本机 Chromium 负责浏览器侧;开发板通过 USB 双头线 ADB 控制 AOSP。各模块独立,可分别启停。

live.local · unknown · unknown
正在连接控制台...
\ No newline at end of file +无人直播系统 · live.local
返回门户首页无人直播 · 本页需与 API 同域(推荐 live.local:8001)

控制平面 · ARM Linux 开发板

无人直播控制中心

ShellCrash 负责代理上网;本机 FFmpeg 处理推流或 HDMI;Neko(Docker Chromium)或本机 Chromium 负责浏览器侧;开发板通过 USB 双头线 ADB 控制 AOSP。各模块独立,可分别启停。

live.local · unknown · unknown
正在连接控制台...
\ No newline at end of file diff --git a/d2ypp2/web-console/out/android.txt b/d2ypp2/web-console/out/android.txt index cbf9725..4ed5230 100644 --- a/d2ypp2/web-console/out/android.txt +++ b/d2ypp2/web-console/out/android.txt @@ -2,6 +2,6 @@ 3:I[3946,["500","static/chunks/500-ea37cc8de90441f7.js","246","static/chunks/246-b5d14933cf331e85.js","357","static/chunks/app/android/page-84550dabda18d658.js"],"default",1] 4:I[4707,[],""] 5:I[6423,[],""] -0:["z_UuUy3mGDwiCWfhwZJVM",[[["",{"children":["android",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["android",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","android","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] +0:["UmN0Ou_Iv2TWI4xcHvY2X",[[["",{"children":["android",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["android",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","android","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] 6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"无人直播系统 · live.local"}],["$","meta","3",{"name":"description","content":"Linux ARM/x86 一键部署的无人直播控制台:YouTube 转播、TikTok HDMI、SRS、Neko 与系统服务"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","meta","5",{"name":"next-size-adjust"}]] 1:null diff --git a/d2ypp2/web-console/out/console.html b/d2ypp2/web-console/out/console.html index 0d8f67d..86c7754 100644 --- a/d2ypp2/web-console/out/console.html +++ b/d2ypp2/web-console/out/console.html @@ -1 +1 @@ -无人直播系统 · live.local
返回门户首页无人直播 · 本页需与 API 同域(推荐 live.local:8001)

控制平面 · ARM Linux 开发板

无人直播控制中心

ShellCrash 负责代理上网;本机 FFmpeg 处理推流或 HDMI;Neko(Docker Chromium)或本机 Chromium 负责浏览器侧;开发板通过 USB 双头线 ADB 控制 AOSP。各模块独立,可分别启停。

live.local · unknown · unknown
正在连接控制台...
\ No newline at end of file +无人直播系统 · live.local
返回门户首页无人直播 · 本页需与 API 同域(推荐 live.local:8001)

控制平面 · ARM Linux 开发板

无人直播控制中心

ShellCrash 负责代理上网;本机 FFmpeg 处理推流或 HDMI;Neko(Docker Chromium)或本机 Chromium 负责浏览器侧;开发板通过 USB 双头线 ADB 控制 AOSP。各模块独立,可分别启停。

live.local · unknown · unknown
正在连接控制台...
\ No newline at end of file diff --git a/d2ypp2/web-console/out/console.txt b/d2ypp2/web-console/out/console.txt index 4ba4be0..81ac4a4 100644 --- a/d2ypp2/web-console/out/console.txt +++ b/d2ypp2/web-console/out/console.txt @@ -2,6 +2,6 @@ 3:I[6367,["500","static/chunks/500-ea37cc8de90441f7.js","246","static/chunks/246-b5d14933cf331e85.js","443","static/chunks/app/console/page-75d851a154677dbc.js"],"default",1] 4:I[4707,[],""] 5:I[6423,[],""] -0:["z_UuUy3mGDwiCWfhwZJVM",[[["",{"children":["console",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["console",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","console","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] +0:["UmN0Ou_Iv2TWI4xcHvY2X",[[["",{"children":["console",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["console",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","console","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] 6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"无人直播系统 · live.local"}],["$","meta","3",{"name":"description","content":"Linux ARM/x86 一键部署的无人直播控制台:YouTube 转播、TikTok HDMI、SRS、Neko 与系统服务"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","meta","5",{"name":"next-size-adjust"}]] 1:null diff --git a/d2ypp2/web-console/out/index.html b/d2ypp2/web-console/out/index.html index 712ccd6..25d631b 100644 --- a/d2ypp2/web-console/out/index.html +++ b/d2ypp2/web-console/out/index.html @@ -1 +1 @@ -无人直播系统 · live.local

总览

live.local · 夜间 · 前台自动刷新 · 最后同步 未同步

直播工作室 · 3D

CPU 1m

负载均值

内存

/ —

磁盘可用

/ —

服务在线

基础服务层

运行时间

自开机

直播进程

  • 暂无直播进程
\ No newline at end of file +无人直播系统 · live.local

总览

live.local · 夜间 · 前台自动刷新 · 最后同步 未同步

直播工作室 · 3D

CPU 1m

负载均值

内存

/ —

磁盘可用

/ —

服务在线

基础服务层

运行时间

自开机

直播进程

  • 暂无直播进程
\ No newline at end of file diff --git a/d2ypp2/web-console/out/index.txt b/d2ypp2/web-console/out/index.txt index 99d54dc..6cc9b72 100644 --- a/d2ypp2/web-console/out/index.txt +++ b/d2ypp2/web-console/out/index.txt @@ -1,7 +1,7 @@ 2:I[9107,[],"ClientPageRoot"] -3:I[1499,["500","static/chunks/500-ea37cc8de90441f7.js","719","static/chunks/719-4dbe9dca4cff8afd.js","246","static/chunks/246-b5d14933cf331e85.js","931","static/chunks/app/page-10361036b8bf1ca2.js"],"default",1] +3:I[1499,["500","static/chunks/500-ea37cc8de90441f7.js","719","static/chunks/719-4dbe9dca4cff8afd.js","246","static/chunks/246-b5d14933cf331e85.js","931","static/chunks/app/page-3c5cf076d3a5e7c5.js"],"default",1] 4:I[4707,[],""] 5:I[6423,[],""] -0:["z_UuUy3mGDwiCWfhwZJVM",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] +0:["UmN0Ou_Iv2TWI4xcHvY2X",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] 6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"无人直播系统 · live.local"}],["$","meta","3",{"name":"description","content":"Linux ARM/x86 一键部署的无人直播控制台:YouTube 转播、TikTok HDMI、SRS、Neko 与系统服务"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","meta","5",{"name":"next-size-adjust"}]] 1:null diff --git a/d2ypp2/web-console/out/shellcrash.html b/d2ypp2/web-console/out/shellcrash.html index 507010f..65192da 100644 --- a/d2ypp2/web-console/out/shellcrash.html +++ b/d2ypp2/web-console/out/shellcrash.html @@ -1 +1 @@ -无人直播系统 · live.local
返回门户首页无人直播 · 本页需与 API 同域(推荐 live.local:8001)

控制平面 · ARM Linux 开发板

无人直播控制中心

ShellCrash 负责代理上网;本机 FFmpeg 处理推流或 HDMI;Neko(Docker Chromium)或本机 Chromium 负责浏览器侧;开发板通过 USB 双头线 ADB 控制 AOSP。各模块独立,可分别启停。

live.local · unknown · unknown
正在连接控制台...
\ No newline at end of file +无人直播系统 · live.local
返回门户首页无人直播 · 本页需与 API 同域(推荐 live.local:8001)

控制平面 · ARM Linux 开发板

无人直播控制中心

ShellCrash 负责代理上网;本机 FFmpeg 处理推流或 HDMI;Neko(Docker Chromium)或本机 Chromium 负责浏览器侧;开发板通过 USB 双头线 ADB 控制 AOSP。各模块独立,可分别启停。

live.local · unknown · unknown
正在连接控制台...
\ No newline at end of file diff --git a/d2ypp2/web-console/out/shellcrash.txt b/d2ypp2/web-console/out/shellcrash.txt index 63c4234..87e111a 100644 --- a/d2ypp2/web-console/out/shellcrash.txt +++ b/d2ypp2/web-console/out/shellcrash.txt @@ -2,6 +2,6 @@ 3:I[3398,["500","static/chunks/500-ea37cc8de90441f7.js","246","static/chunks/246-b5d14933cf331e85.js","6","static/chunks/app/shellcrash/page-3d8615ae919b9119.js"],"default",1] 4:I[4707,[],""] 5:I[6423,[],""] -0:["z_UuUy3mGDwiCWfhwZJVM",[[["",{"children":["shellcrash",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["shellcrash",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","shellcrash","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] +0:["UmN0Ou_Iv2TWI4xcHvY2X",[[["",{"children":["shellcrash",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["shellcrash",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","shellcrash","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/693f7950f3222bce.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","data-theme":"dark","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_1e4310 __variable_c3aa02 font-sans antialiased","children":[["$","div",null,{"className":"app-bg-layer","aria-hidden":true}],["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]]}]}]],null],null],["$L6",null]]]] 6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"无人直播系统 · live.local"}],["$","meta","3",{"name":"description","content":"Linux ARM/x86 一键部署的无人直播控制台:YouTube 转播、TikTok HDMI、SRS、Neko 与系统服务"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","meta","5",{"name":"next-size-adjust"}]] 1:null