forked from manzt/built-with-anywidget
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdownload.ts
112 lines (101 loc) · 2.93 KB
/
download.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { z } from "zod";
import sharp from "sharp";
type MimeType = z.infer<typeof AssetSchema>["mimeType"];
function filename(repo: string, mimeType: MimeType) {
let ext = mimeType === "image/svg+xml" ? "svg" : mimeType.split("/")[1];
return `${repo.replace("/", "__")}.${ext}`;
}
async function num_pages(gif: Uint8Array) {
let img = sharp(new Uint8Array(gif!.buffer));
let meta = await img.metadata();
return meta.pages ?? 0;
}
let RepoSchema = z.object({
repo: z.string(),
description: z.string(),
sourceUrl: z.string().optional(),
image: z.string().optional(),
gif: z.string().optional(),
});
type Asset = z.infer<typeof AssetSchema>;
let AssetSchema = z.object({
bytes: z.instanceof(Uint8Array),
mimeType: z.enum([
"image/gif",
"image/png",
"image/jpeg",
"image/svg+xml",
"application/octet-stream",
]).transform((v) => {
if (v === "application/octet-stream") {
return "image/gif";
}
return v;
}),
});
if (import.meta.main) {
let repos = z.array(RepoSchema).parse(
JSON.parse(Deno.readTextFileSync("assets/manifest.json")),
);
await Deno.mkdir("assets", { recursive: true });
let assets = new Map<string, { image: string; gif?: string }>();
for (let repo of repos) {
// Already downloaded and converted
if (repo.gif && repo.image) {
continue;
}
let asset: Asset;
if (repo.gif && !repo.image) {
asset = {
mimeType: "image/gif",
bytes: Deno.readFileSync(`assets/${repo.gif}`),
};
} else if (repo.sourceUrl) {
asset = await fetch(repo.sourceUrl)
.then(async (response) =>
AssetSchema.parse({
mimeType: response.headers.get("content-type"),
bytes: new Uint8Array(await response.arrayBuffer()),
})
);
} else {
// No sourceUrl, no gif, no image
continue;
}
switch (asset.mimeType) {
case "image/gif": {
// save both the gif and the middle page as a jpeg
let npages = await num_pages(asset.bytes);
// Get the middle page
let img = sharp(asset.bytes, {
pages: 1,
page: Math.floor(npages / 2),
});
let imgName = filename(repo.repo, "image/jpeg");
await img.jpeg().toFile(`assets/${imgName}`);
let gifName = filename(repo.repo, asset.mimeType);
Deno.writeFileSync(`assets/${gifName}`, asset.bytes);
assets.set(repo.repo, { image: imgName, gif: gifName });
break;
}
case "image/png":
case "image/svg+xml":
case "image/jpeg": {
// just save the image
let imgName = filename(repo.repo, asset.mimeType);
Deno.writeFileSync(`assets/${imgName}`, asset.bytes);
assets.set(repo.repo, { image: imgName });
}
}
}
let completeManifest = repos
.map((repo) => ({
repo: repo.repo,
description: repo.description,
sourceUrl: repo.sourceUrl,
image: assets.get(repo.repo)?.image ?? repo.image,
gif: assets.get(repo.repo)?.gif ?? repo.gif,
}));
let finalManifest = JSON.stringify(completeManifest, null, "\t") + "\n";
Deno.writeTextFileSync("assets/manifest.json", finalManifest);
}