Publish YouTubeDL 1.4.5 and website on Gitea
Check extension and helper / check (push) Canceled after 0s
Check extension and helper / check (push) Canceled after 0s
This commit is contained in:
commit
5f2aad00f4
97 files changed
+8451
No files matched your search
@@ -0,0 +1,97 @@
|
||||
"""Exercise the real offline installer with unusable external tools and proxies."""
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
ARTIFACTS = ROOT / "test-artifacts"
|
||||
ARTIFACTS.mkdir(exist_ok=True)
|
||||
INSTALLER = ROOT / "dist/YouTubeDL-Helper-Setup.exe"
|
||||
environment = {**os.environ, "PATH": str(Path(os.environ.get("SystemRoot", r"C:\Windows")) / "System32"),
|
||||
"PYTHONHOME": "C:/NONEXISTENT", "PYTHONPATH": "C:/NONEXISTENT", "PYTHONNOUSERSITE": "1",
|
||||
"HTTP_PROXY": "http://127.0.0.1:9", "HTTPS_PROXY": "http://127.0.0.1:9", "ALL_PROXY": "http://127.0.0.1:9"}
|
||||
|
||||
|
||||
def run(*args):
|
||||
result = subprocess.run([str(item) for item in args], env=environment, capture_output=True,
|
||||
encoding="utf-8", errors="replace", timeout=180)
|
||||
if result.returncode:
|
||||
raise RuntimeError(json.dumps({"code": result.returncode, "stdout": result.stdout[-500:], "stderr": result.stderr[-2500:]}))
|
||||
return result
|
||||
|
||||
|
||||
def picker(manager, folder):
|
||||
import base64
|
||||
encoded = base64.b64encode(json.dumps(str(folder)).encode()).decode()
|
||||
process = subprocess.Popen([str(manager), "--pick-folder", "--initial-folder", encoded], env=environment,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
user32 = ctypes.windll.user32
|
||||
callback_type = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p)
|
||||
dialogs = []
|
||||
def callback(window, unused):
|
||||
pid = ctypes.c_ulong(); user32.GetWindowThreadProcessId(window, ctypes.byref(pid))
|
||||
if pid.value == process.pid:
|
||||
name = ctypes.create_unicode_buffer(256); user32.GetClassNameW(window, name, 256)
|
||||
if name.value == "#32770" and user32.IsWindowVisible(window): dialogs.append(window)
|
||||
return True
|
||||
deadline = time.monotonic() + 15
|
||||
handler = callback_type(callback)
|
||||
while not dialogs and time.monotonic() < deadline:
|
||||
user32.EnumWindows(handler, 0); time.sleep(0.1)
|
||||
assert dialogs, "The bundled Windows folder picker must open"
|
||||
# Select its preselected existing folder, including Unicode in the path.
|
||||
user32.PostMessageW(ctypes.c_void_p(dialogs[0]), 0x0111, 1, 0) # WM_COMMAND / IDOK
|
||||
output, errors = process.communicate(timeout=15)
|
||||
assert process.returncode == 0, errors.decode("utf-8", errors="replace")
|
||||
assert Path(json.loads(output)) == folder
|
||||
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="offline-bundle-", dir=ARTIFACTS) as temporary:
|
||||
parent = Path(temporary)
|
||||
application = parent / "Helper"
|
||||
legacy = application / ".runtime"; legacy.mkdir(parents=True)
|
||||
(legacy / "completed-jobs.json").write_text("[]")
|
||||
first = run(INSTALLER, "--silent", "--no-register", "--target-root", application)
|
||||
assert (application / "data/completed-jobs.json").read_text() == "[]"
|
||||
marker = json.loads((application / "installation.json").read_text(encoding="utf-8-sig"))
|
||||
release = Path(marker["current"])
|
||||
python = release / "runtime/python/python.exe"
|
||||
measured = json.loads(run(python, "-I", "-B", "-c",
|
||||
"import json,sys; from host.media import capabilities,tool; print(json.dumps({'python':sys.executable,'path':sys.path,'hardware':capabilities(),'tools':{k:tool(k) for k in ('node','ffmpeg','ffprobe')}}))").stdout)
|
||||
assert measured["hardware"]["ready"]
|
||||
assert measured["hardware"]["bundle"]["mode"] == "autonomous"
|
||||
assert {"h264", "hevc", "av1"} <= set(measured["hardware"]["nvenc"]), measured["hardware"]
|
||||
assert Path(measured["python"]).is_relative_to(release)
|
||||
assert all(Path(path).is_relative_to(release) for path in measured["tools"].values())
|
||||
assert all(Path(path).is_relative_to(release) for path in measured["path"])
|
||||
picker(application / "YouTubeDL-Manager.exe", ARTIFACTS)
|
||||
preserved = release / "user-kept.mp4"; preserved.write_bytes(b"user file")
|
||||
history = application / "data/completed-jobs.json"; history.parent.mkdir(exist_ok=True); history.write_text("[]")
|
||||
# Reinstall beside the running copy; an old DLL handle must not prevent repair.
|
||||
handle = (release / "runtime/python/python313.dll").open("rb")
|
||||
try: run(INSTALLER, "--silent", "--no-register", "--target-root", application)
|
||||
finally: handle.close()
|
||||
current = Path(json.loads((application / "installation.json").read_text(encoding="utf-8-sig"))["current"])
|
||||
assert current != release and current.is_dir()
|
||||
manager = application / "YouTubeDL-Manager.exe"
|
||||
run(manager, "--uninstall", "--silent", "--target-root", application)
|
||||
assert preserved.read_bytes() == b"user file" and history.read_text() == "[]"
|
||||
assert not current.exists() and not python.exists()
|
||||
deadline = time.monotonic() + 15
|
||||
while manager.exists() and time.monotonic() < deadline: time.sleep(0.1)
|
||||
assert not manager.exists(), "The uninstaller must remove its own installed executable"
|
||||
# Payload damage must be rejected before registering or installing any tools.
|
||||
damaged = parent / "damaged.exe"
|
||||
payload = bytearray(INSTALLER.read_bytes()); offset = payload.index(b"PK\x03\x04"); payload[offset + 100] ^= 1
|
||||
damaged.write_bytes(payload)
|
||||
invalid = subprocess.run([str(damaged), "--silent", "--no-register", "--target-root", str(parent / "Invalid")],
|
||||
env=environment, capture_output=True, encoding="utf-8", timeout=60)
|
||||
assert invalid.returncode != 0 and "Контрольная сумма" in invalid.stderr, invalid.stderr
|
||||
(ARTIFACTS / "offline-bundle.json").write_text(json.dumps({"offlineInstallation": "passed", "isolatedRuntime": "passed",
|
||||
"folderPicker": "passed", "repairWhileOldFilesOpen": "passed", "uninstallPreservesUserMedia": "passed", "corruptedPayload": "rejected",
|
||||
"versions": measured["hardware"]["dependencies"], "nvenc": measured["hardware"]["nvenc"]}, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
print("Offline bundle passed: isolated runtime, blocked proxies, Windows picker, NVENC, repair, scoped uninstall and damaged-payload rejection.")
|
||||
Reference in new issue
Block a user