This commit is contained in:
eric
2026-03-29 03:51:50 -05:00
parent 7cab3f27b8
commit 915412a819
6 changed files with 119 additions and 6 deletions

View File

@@ -17,6 +17,7 @@ from pathlib import Path
from typing import Any
from src.android_control import _adb_prefix, _adb_text, _run_cmd, adb_available
from src.scrcpy_vendor import ensure_scrcpy_jar
BASE_DIR = Path(__file__).resolve().parent.parent
REMOTE_JAR = "/data/local/tmp/scrcpy-web-hub.jar"
@@ -65,10 +66,18 @@ def scrcpy_stream_info() -> dict[str, Any]:
"server_path": str(jar) if jar else None,
"server_version": ver,
"remote_jar": REMOTE_JAR,
"hint_zh": "将官方 scrcpy 发行包中的 scrcpy-server或 scrcpy-server.jar放到项目 vendor/scrcpy-server.jar"
"或设置环境变量 SCRCPY_SERVER_JAR版本字符串须与该 jar 完全一致(默认可配 vendor/scrcpy-server.version 或 SCRCPY_SERVER_VERSION",
"hint_en": "Place scrcpy-server from the official scrcpy release in vendor/scrcpy-server.jar, "
"or set SCRCPY_SERVER_JAR; the version string must match the jar (vendor/scrcpy-server.version or SCRCPY_SERVER_VERSION).",
"hint_zh": (
"服务启动时会尝试从 Genymobile 官方 Release 拉取与 vendor/scrcpy-server.version 匹配的 scrcpy-server"
"离线环境可预置 vendor/scrcpy-server.jar 或设置 SCRCPY_SERVER_JAR。"
if not jar
else "scrcpy-server 已就绪。"
),
"hint_en": (
"On startup the hub tries to download the matching scrcpy-server from Genymobile releases; "
"for offline use place vendor/scrcpy-server.jar or set SCRCPY_SERVER_JAR."
if not jar
else "scrcpy-server is ready."
),
}
@@ -156,9 +165,12 @@ async def open_scrcpy_h264_stream(
raise RuntimeError("adb is not installed")
jar = resolve_scrcpy_server_jar()
if not jar:
ensure_scrcpy_jar(BASE_DIR)
jar = resolve_scrcpy_server_jar()
if not jar:
raise RuntimeError(
"scrcpy-server not found; set SCRCPY_SERVER_JAR or add vendor/scrcpy-server.jar",
"scrcpy-server 不可用:自动拉取失败或处于离线;请检查网络后重启服务,或预置 vendor/scrcpy-server.jar",
)
version = default_server_version()

85
src/scrcpy_vendor.py Normal file
View File

@@ -0,0 +1,85 @@
"""自动准备官方 scrcpy-server与 vendor/scrcpy-server.version 版本一致),供 Web 真流 adb push 使用。"""
from __future__ import annotations
import os
import sys
import urllib.error
import urllib.request
from pathlib import Path
# 官方发行资产名scrcpy-server-v{version}(无扩展名,实为 JAR
_GITHUB_DL = "https://github.com/Genymobile/scrcpy/releases/download/v{tag}/scrcpy-server-v{tag}"
_MIN_BYTES = 8_000
def _read_version(repo_root: Path) -> str:
env = (os.environ.get("SCRCPY_SERVER_VERSION") or "").strip().lstrip("v")
if env:
return env
vf = repo_root / "vendor" / "scrcpy-server.version"
if vf.is_file():
line = vf.read_text(encoding="utf-8").splitlines()[0].strip().lstrip("v")
if line:
return line
return "3.3.3"
def ensure_scrcpy_jar(repo_root: Path) -> tuple[bool, str]:
"""
若 vendor/scrcpy-server.jar 不存在或过小,则从 Genymobile GitHub Release 下载。
可通过环境变量 SKIP_SCRCPY_SERVER_FETCH=1 跳过。
"""
if os.environ.get("SKIP_SCRCPY_SERVER_FETCH", "").strip().lower() in ("1", "true", "yes", "on"):
return True, "skip fetch (SKIP_SCRCPY_SERVER_FETCH)"
vendor_dir = repo_root / "vendor"
dest = vendor_dir / "scrcpy-server.jar"
env_jar = (os.environ.get("SCRCPY_SERVER_JAR") or "").strip()
if env_jar:
p = Path(env_jar).expanduser()
if p.is_file() and p.stat().st_size >= _MIN_BYTES:
return True, "using SCRCPY_SERVER_JAR"
if dest.is_file() and dest.stat().st_size >= _MIN_BYTES:
return True, "vendor/scrcpy-server.jar ok"
tag = _read_version(repo_root)
url = _GITHUB_DL.format(tag=tag)
vendor_dir.mkdir(parents=True, exist_ok=True)
tmp = dest.with_suffix(".jar.part")
try:
req = urllib.request.Request(
url,
headers={"User-Agent": "douyinyoutube-live-hub/scrcpy-bootstrap"},
method="GET",
)
with urllib.request.urlopen(req, timeout=120) as resp:
data = resp.read()
except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError, OSError) as e:
return False, f"download failed ({url}): {e}"
if len(data) < _MIN_BYTES:
return False, f"download too small ({len(data)} bytes), check version {tag}"
if not data.startswith(b"PK"):
return False, "downloaded file does not look like a JAR (expected PK header)"
try:
tmp.write_bytes(data)
os.replace(tmp, dest)
except OSError as e:
return False, f"write vendor/scrcpy-server.jar failed: {e}"
return True, f"fetched scrcpy-server v{tag} -> vendor/scrcpy-server.jar"
def main() -> int:
root = Path(__file__).resolve().parent.parent
ok, msg = ensure_scrcpy_jar(root)
print(msg, file=sys.stderr if not ok else sys.stdout)
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())