Files
gitlab-instance-0a899031_do…/src/scrcpy_vendor.py
2026-03-29 04:00:09 -05:00

147 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""自动准备官方 scrcpy-server与 vendor/scrcpy-server.version 版本一致),供 Web 真流 adb push 使用。"""
from __future__ import annotations
import os
import sys
import time
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
_PER_URL_ATTEMPTS = 3
_PER_URL_DELAY_S = 2.0
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 _expand_download_url(template: str, tag: str) -> str:
return template.replace("{tag}", tag).replace("{version}", tag)
def _download_urls_to_try(tag: str) -> list[str]:
"""顺序SCRCPY_SERVER_DOWNLOAD_URL → SCRCPY_SERVER_DOWNLOAD_URLS →默认可选GitHub。"""
urls: list[str] = []
single = (os.environ.get("SCRCPY_SERVER_DOWNLOAD_URL") or "").strip()
if single:
urls.append(_expand_download_url(single, tag))
raw = (os.environ.get("SCRCPY_SERVER_DOWNLOAD_URLS") or "").strip()
if raw:
for part in raw.split(","):
u = part.strip()
if not u:
continue
uu = _expand_download_url(u, tag)
if uu not in urls:
urls.append(uu)
no_github = os.environ.get("SCRCPY_SERVER_DOWNLOAD_NO_GITHUB", "").strip().lower() in (
"1",
"true",
"yes",
"on",
)
gh = _GITHUB_DL.format(tag=tag)
if not no_github and gh not in urls:
urls.append(gh)
seen: set[str] = set()
out: list[str] = []
for u in urls:
if u not in seen:
seen.add(u)
out.append(u)
return out
def _fetch_url(url: str) -> tuple[bool, bytes | None, str]:
req = urllib.request.Request(
url,
headers={"User-Agent": "douyinyoutube-live-hub/scrcpy-bootstrap"},
method="GET",
)
last_err = ""
for attempt in range(1, _PER_URL_ATTEMPTS + 1):
try:
with urllib.request.urlopen(req, timeout=120) as resp:
data = resp.read()
return True, data, ""
except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError, OSError) as e:
last_err = str(e)
if attempt < _PER_URL_ATTEMPTS:
time.sleep(_PER_URL_DELAY_S)
return False, None, last_err
def ensure_scrcpy_jar(repo_root: Path) -> tuple[bool, str]:
"""
若 vendor/scrcpy-server.jar 不存在或过小,则按 URL 列表下载。
环境变量:
SKIP_SCRCPY_SERVER_FETCH=1 — 跳过
SCRCPY_SERVER_DOWNLOAD_URL — 优先下载地址,可用 {tag}/{version}
SCRCPY_SERVER_DOWNLOAD_URLS — 逗号分隔多条,先于 GitHub
SCRCPY_SERVER_DOWNLOAD_NO_GITHUB=1 — 仅用上面自定义 URL不回退 GitHub
"""
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)
urls = _download_urls_to_try(tag)
if not urls:
return False, "未配置任何下载源SCRCPY_SERVER_DOWNLOAD_NO_GITHUB=1 且未设置 SCRCPY_SERVER_DOWNLOAD_URL(S)"
vendor_dir.mkdir(parents=True, exist_ok=True)
tmp = dest.with_suffix(".jar.part")
last_fail = ""
for url in urls:
ok, data, err = _fetch_url(url)
if not ok or data is None:
last_fail = f"{url}: {err}"
continue
if len(data) < _MIN_BYTES:
last_fail = f"{url}: too small ({len(data)} bytes)"
continue
if not data.startswith(b"PK"):
last_fail = f"{url}: not a JAR (missing PK header)"
continue
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 (via {url})"
return False, f"download failed after {len(urls)} source(s): {last_fail}"
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())