izuemon commited on
Commit
d866e47
·
verified ·
1 Parent(s): 0d2e983

Update generate_html.cjs

Browse files
Files changed (1) hide show
  1. generate_html.cjs +80 -27
generate_html.cjs CHANGED
@@ -1,41 +1,94 @@
1
- // generate_html.js
2
  const Packager = require("@turbowarp/packager");
3
  const fetch = require("cross-fetch").default;
4
- const fs = require("fs");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  async function main() {
7
- const id = process.argv[2];
8
- const optionsJsonPath = process.argv[3];
9
 
10
- if (!id) throw new Error("project id required.");
11
- const optionsInput = JSON.parse(fs.readFileSync(optionsJsonPath, "utf8"));
12
 
13
- // Scratchプロジェクトの取得
14
- const metaRes = await fetch(`https://trampoline.turbowarp.org/api/projects/${id}`);
15
- const meta = await metaRes.json();
16
- const token = meta.project_token;
17
- const projectRes = await fetch(`https://projects.scratch.mit.edu/${id}?token=${token}`);
18
- const projectData = await projectRes.arrayBuffer();
19
 
20
- // ロード
21
- const loaded = await Packager.loadProject(projectData);
22
 
23
- // Packagerの生成
24
- const pack = new Packager.Packager();
25
- pack.project = loaded;
26
 
27
- // のオプションを維持しつつ上書き
28
- Object.assign(pack.options, optionsInput);
 
 
29
 
30
- // パッケージ化
31
- const { data, type } = await pack.package();
 
 
 
 
32
 
33
- if (type !== "text/html") throw new Error("not html");
 
 
34
 
35
- // HTMLとして出力
36
- process.stdout.write(Buffer.from(data).toString("utf8"));
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
- main().catch(err => {
39
- console.error(err);
40
- process.exit(1);
 
41
  });
 
 
1
  const Packager = require("@turbowarp/packager");
2
  const fetch = require("cross-fetch").default;
3
+
4
+ async function fetchProjectData(projectId) {
5
+ // Node.js では trampoline ではなく Scratch API を直接使う
6
+ const metaRes = await fetch(`https://api.scratch.mit.edu/projects/${encodeURIComponent(projectId)}`);
7
+ if (!metaRes.ok) {
8
+ throw new Error(`project metadata fetch failed: ${metaRes.status}`);
9
+ }
10
+
11
+ const meta = await metaRes.json();
12
+ const token = meta.project_token;
13
+ if (!token) {
14
+ throw new Error("project_token が取得できませんでした");
15
+ }
16
+
17
+ const projectRes = await fetch(
18
+ `https://projects.scratch.mit.edu/${encodeURIComponent(projectId)}?token=${encodeURIComponent(token)}`
19
+ );
20
+ if (!projectRes.ok) {
21
+ throw new Error(`project data fetch failed: ${projectRes.status}`);
22
+ }
23
+
24
+ return Buffer.from(await projectRes.arrayBuffer());
25
+ }
26
+
27
+ async function imageFromUrl(url) {
28
+ if (!url) return undefined;
29
+
30
+ const res = await fetch(url);
31
+ if (!res.ok) {
32
+ throw new Error(`image fetch failed: ${res.status}`);
33
+ }
34
+
35
+ const contentType = (res.headers.get("content-type") || "image/png").split(";")[0].trim();
36
+ const buffer = Buffer.from(await res.arrayBuffer());
37
+ return new Packager.Image(contentType, buffer);
38
+ }
39
+
40
+ function bool(v, fallback = false) {
41
+ if (v === undefined || v === null || v === "") return fallback;
42
+ if (typeof v === "boolean") return v;
43
+ return String(v).toLowerCase() === "true" || v === "1" || String(v).toLowerCase() === "yes";
44
+ }
45
 
46
  async function main() {
47
+ const projectId = process.argv[2];
48
+ const optionsJson = process.argv[3];
49
 
50
+ if (!projectId) throw new Error("project id required");
 
51
 
52
+ const options = optionsJson ? JSON.parse(require("fs").readFileSync(optionsJson, "utf8")) : {};
53
+ const projectData = await fetchProjectData(projectId);
 
 
 
 
54
 
55
+ const loadedProject = await Packager.loadProject(projectData);
 
56
 
57
+ const packager = new Packager.Packager();
58
+ packager.project = loadedProject;
 
59
 
60
+ // ここでは「在する値だけ」上書きする
61
+ if ("turbo" in options) packager.options.turbo = bool(options.turbo);
62
+ if ("compiler" in options) packager.options.compiler = bool(options.compiler);
63
+ if ("warpTimer" in options) packager.options.warpTimer = bool(options.warpTimer);
64
 
65
+ if (typeof options.customJs === "string") {
66
+ packager.options.custom.js = options.customJs;
67
+ }
68
+ if (typeof options.customCss === "string") {
69
+ packager.options.custom.css = options.customCss;
70
+ }
71
 
72
+ if (typeof options.title === "string" && options.title.trim() !== "") {
73
+ packager.options.app.title = options.title;
74
+ }
75
 
76
+ // 画像系は null を入れず、指定された時だけ設定する
77
+ const icon = await imageFromUrl(options.iconUrl);
78
+ if (icon) {
79
+ packager.options.app.icon = icon;
80
+ }
81
+
82
+ const loadingImage = await imageFromUrl(options.loadingImageUrl);
83
+ if (loadingImage) {
84
+ packager.options.loading.image = loadingImage;
85
+ }
86
+
87
+ const result = await packager.package();
88
+ process.stdout.write(Buffer.from(result.data).toString("utf8"));
89
  }
90
+
91
+ main().catch((err) => {
92
+ console.error(err);
93
+ process.exit(1);
94
  });