内容分四块: 1、产品规划产出 —— MCN 短视频整合营销工作台的①段五份(1a 需求/1b 竞品/1c 画像/1d 策略/1e 场景)、②段两份(2a 功能/2b 布局)、③段界面(DESIGN.md 契约与令牌表 + mcn-workbench.html 原型 + 实测/会诊/审查三份 + 23 张闸门截图)。 2、开源竞品调研 —— 5 个内容工作台项目的取证原始件与 1b 系列分析文档。 3、参考资料 —— 竞品视频抽帧 1145 张 + 2 个源视频 + 功能点截图。 4、机制侧 —— 协作脚本与状态台账、工作区记忆日志、抽帧/OCR 脚本。 .gitignore 只排运行时日志、脚本备份副本与一次性探针输出,其余按原样入库。
64 lines
2.8 KiB
Python
64 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""OpenCreator 文件树分片拉取(避 recursive=1 整树响应过大)
|
||
来源:GitHub git/trees API —— /repos/krillinai/OpenCreator/git/trees/<sha>?recursive=1
|
||
用法:python _opencreator_tree.py # 拉取并把每片落盘到 取证/opencreator/
|
||
输出:tree_<name>.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()
|