MCPcopy Create free account
hub / github.com/heygen-com/hyperframes / saveLottieAnimations

Function saveLottieAnimations

packages/cli/src/capture/mediaCapture.ts:30–106  ·  view source on GitHub ↗
(
  discoveredLotties: DiscoveredLottie[],
  lottieDir: string,
)

Source from the content-addressed store, hash-verified

28 */
29// fallow-ignore-next-line complexity
30export async function saveLottieAnimations(
31 discoveredLotties: DiscoveredLottie[],
32 lottieDir: string,
33): Promise<number> {
34 let savedCount = 0;
35 const savedHashes = new Set<string>(); // Deduplicate by content
36
37 for (let li = 0; li < discoveredLotties.length && li < 10; li++) {
38 const lottieItem = discoveredLotties[li]!;
39 try {
40 let jsonData: string | undefined;
41
42 if (lottieItem.data) {
43 // Already have the JSON data from network interception
44 jsonData = JSON.stringify(lottieItem.data);
45 } else if (lottieItem.url) {
46 // SSRF guard — safeFetch re-checks the denylist on every redirect hop
47 const res = await safeFetch(lottieItem.url, {
48 signal: AbortSignal.timeout(10000),
49 headers: { "User-Agent": "HyperFrames/1.0" },
50 });
51 if (!res || !res.ok) continue;
52 const buf = Buffer.from(await res.arrayBuffer());
53
54 if (lottieItem.url.endsWith(".lottie")) {
55 // dotLottie is a ZIP — extract the animation JSON
56 try {
57 const AdmZip = (await import("adm-zip")).default;
58 const zip = new AdmZip(buf);
59 const entries = zip.getEntries();
60 // Look for animation JSON in both v1 (animations/) and v2 (a/) paths
61 const animEntry = entries.find(
62 (e) =>
63 (e.entryName.startsWith("a/") || e.entryName.startsWith("animations/")) &&
64 e.entryName.endsWith(".json"),
65 );
66 if (animEntry) {
67 jsonData = animEntry.getData().toString("utf-8");
68 }
69 } catch {
70 // adm-zip not available or extraction failed — save raw .lottie
71 const hash = buf.toString("base64").slice(0, 100);
72 if (savedHashes.has(hash)) continue;
73 savedHashes.add(hash);
74 writeFileSync(join(lottieDir, `animation-${savedCount}.lottie`), buf);
75 savedCount++;
76 continue;
77 }
78 } else {
79 // Plain JSON file
80 jsonData = buf.toString("utf-8");
81 }
82 }
83
84 if (jsonData) {
85 // Deduplicate by content hash (first 100 chars of stringified JSON)
86 const hash = jsonData.slice(0, 200);
87 if (savedHashes.has(hash)) continue;

Callers 1

captureWebsiteFunction · 0.85

Calls 4

safeFetchFunction · 0.85
fromMethod · 0.80
addMethod · 0.80
findMethod · 0.65

Tested by

no test coverage detected