# -*- coding: utf-8 -*- """OpenCreator 文件树分片拉取(避 recursive=1 整树响应过大) 来源:GitHub git/trees API —— /repos/krillinai/OpenCreator/git/trees/?recursive=1 用法:python _opencreator_tree.py # 拉取并把每片落盘到 取证/opencreator/ 输出:tree_.json(逐片),并打印 truncated 与条目数(可复算) """ import json, os, sys, time, urllib.request, urllib.error REPO = "krillinai/OpenCreator" HERE = os.path.dirname(os.path.abspath(__file__)) OUT = os.path.join(HERE, "opencreator") os.makedirs(OUT, exist_ok=True) # 顶层目录 -> sha(取自第 1 棒已拉的 opencreator.tree.top.json,2026-10-07 16:14) TOPS = { ".github": "6a9815862c407991905d5d57cb41fcd1082acf70", "apps": "45bca5790d008582b2f0b83acd5d0282c17f1e02", "assets": "44fa661ea45db7aab343c7d541826a622234d2df", "packages": "1f1151f4b61203f37cb39a716fc5d750f9e773b2", "resources": "7a1e6ecd1b55ae1ac8cf7d88aaf5155a860ee4f2", "runtime": "0c8a1a4247afcc15dbd04c7995b58530a1ac1e8f", "scripts": "f28df95991fe5c753464d5049b99fdddda6cc27c", "skills": "40072888acdf2a87b463f174842558c52ba36168", "template": "553e77dffa5a1d746cda0745c22f9cf60897b00b", "docs/specs":"8d12278b08121a91ec71db6c83ce0727a6669817", } def get(url, tries=3): last = None for i in range(tries): try: req = urllib.request.Request(url, headers={ "User-Agent": "wb-research/1.0", "Accept": "application/vnd.github+json", }) with urllib.request.urlopen(req, timeout=45) as r: return json.loads(r.read().decode("utf-8")) except Exception as e: last = e sys.stderr.write(" retry %d %s -> %s\n" % (i + 1, url, e)) time.sleep(2) raise last def main(): summary = {} for name, sha in TOPS.items(): url = "https://api.github.com/repos/%s/git/trees/%s?recursive=1" % (REPO, sha) d = get(url) safe = name.replace("/", "_") p = os.path.join(OUT, "tree_%s.json" % safe) with open(p, "w", encoding="utf-8") as f: json.dump(d, f, ensure_ascii=False, indent=1) n = len(d.get("tree", [])) blobn = sum(1 for e in d.get("tree", []) if e.get("type") == "blob") summary[name] = {"sha": sha, "truncated": d.get("truncated", False), "entries": n, "blobs": blobn, "file": os.path.basename(p)} print("%-12s truncated=%-5s entries=%-5d blobs=%-5d -> %s" % (name, d.get("truncated", False), n, blobn, os.path.basename(p))) with open(os.path.join(OUT, "_tree_summary.json"), "w", encoding="utf-8") as f: json.dump(summary, f, ensure_ascii=False, indent=1) if __name__ == "__main__": main()