Files
FunnyGirl/Scripts/download_mobile_fsr_api.py
T
2026-05-19 13:42:41 +07:00

107 lines
3.4 KiB
Python

#!/usr/bin/env python3
import base64
import json
import os
import shutil
import sys
import urllib.error
import urllib.request
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
UPROJECT = PROJECT_ROOT / "FunnyGirl.uproject"
DEST = PROJECT_ROOT / "Plugins" / "MobileFSR"
BRANCH = os.environ.get("MOBILE_FSR_BRANCH", "5.6.1-release")
TOKEN = os.environ.get("GITHUB_TOKEN", "")
OWNER = "EpicGames"
REPO = "UnrealEngine"
SOURCE_PATH = "Engine/Plugins/Runtime/MobileFSR"
API_ROOT = f"https://api.github.com/repos/{OWNER}/{REPO}/contents"
def request_json(url):
request = urllib.request.Request(url)
request.add_header("Accept", "application/vnd.github+json")
request.add_header("X-GitHub-Api-Version", "2022-11-28")
if TOKEN:
request.add_header("Authorization", f"Bearer {TOKEN}")
try:
with urllib.request.urlopen(request) as response:
return json.loads(response.read().decode("utf-8"))
except urllib.error.HTTPError as error:
body = error.read().decode("utf-8", errors="replace")
raise RuntimeError(f"GitHub API failed: HTTP {error.code}\n{body}") from error
def download_file(api_url, output_path):
data = request_json(api_url)
encoding = data.get("encoding")
content = data.get("content")
if encoding != "base64" or content is None:
raise RuntimeError(f"Unsupported file response for {api_url}")
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_bytes(base64.b64decode(content))
def download_dir(source_path, output_dir):
url = f"{API_ROOT}/{source_path}?ref={BRANCH}"
entries = request_json(url)
if not isinstance(entries, list):
raise RuntimeError(f"Expected directory listing for {source_path}")
for entry in entries:
name = entry["name"]
entry_type = entry["type"]
if entry_type == "dir":
download_dir(entry["path"], output_dir)
elif entry_type == "file":
rel_path = Path(entry["path"]).relative_to(SOURCE_PATH)
print(f"Downloading {rel_path}")
download_file(entry["url"], output_dir / rel_path)
else:
print(f"Skipping {entry['path']} ({entry_type})")
def enable_plugin():
data = json.loads(UPROJECT.read_text())
plugins = data.setdefault("Plugins", [])
for plugin in plugins:
if plugin.get("Name") == "MobileFSR":
plugin["Enabled"] = True
break
else:
plugins.append({"Name": "MobileFSR", "Enabled": True})
UPROJECT.write_text(json.dumps(data, indent="\t") + "\n")
def main():
if not TOKEN:
print("GITHUB_TOKEN is required for private EpicGames/UnrealEngine access.", file=sys.stderr)
return 1
tmp_dest = DEST.with_name(".MobileFSR.download")
shutil.rmtree(tmp_dest, ignore_errors=True)
shutil.rmtree(DEST, ignore_errors=True)
tmp_dest.mkdir(parents=True)
print(f"Downloading MobileFSR from {OWNER}/{REPO}:{BRANCH}")
download_dir(SOURCE_PATH, tmp_dest)
if not (tmp_dest / "MobileFSR.uplugin").exists():
print("MobileFSR.uplugin was not downloaded; aborting.", file=sys.stderr)
return 1
shutil.rmtree(DEST, ignore_errors=True)
shutil.move(str(tmp_dest), str(DEST))
enable_plugin()
print(f"Installed MobileFSR to {DEST}")
print(f"Enabled MobileFSR in {UPROJECT}")
return 0
if __name__ == "__main__":
raise SystemExit(main())