({ args })
| 53 | json: { type: "boolean", description: "Output as JSON", default: false }, |
| 54 | }, |
| 55 | async run({ args }) { |
| 56 | const project = resolveProject(args.dir); |
| 57 | const html = readFileSync(project.indexPath, "utf-8"); |
| 58 | |
| 59 | ensureDOMParser(); |
| 60 | const parsed = parseHtml(html); |
| 61 | |
| 62 | const tracks = new Set(parsed.elements.map((el) => el.zIndex)); |
| 63 | const maxEnd = parsed.elements.reduce( |
| 64 | (max, el) => Math.max(max, el.startTime + el.duration), |
| 65 | 0, |
| 66 | ); |
| 67 | // Read actual dimensions from root composition element |
| 68 | const widthMatch = |
| 69 | html.match(/data-composition-id[^>]*data-width=["'](\d+)["']/) || |
| 70 | html.match(/data-width=["'](\d+)["'][^>]*data-composition-id/); |
| 71 | const heightMatch = |
| 72 | html.match(/data-composition-id[^>]*data-height=["'](\d+)["']/) || |
| 73 | html.match(/data-height=["'](\d+)["'][^>]*data-composition-id/); |
| 74 | const fallback = CANVAS_DIMENSIONS[parsed.resolution]; |
| 75 | const width = widthMatch?.[1] ? parseInt(widthMatch[1], 10) : fallback.width; |
| 76 | const height = heightMatch?.[1] ? parseInt(heightMatch[1], 10) : fallback.height; |
| 77 | const resolution = `${width}x${height}`; |
| 78 | const duration = durationFromHtml(html, maxEnd); |
| 79 | const size = totalSize(project.dir); |
| 80 | |
| 81 | const typeCounts: Record<string, number> = {}; |
| 82 | for (const el of parsed.elements) { |
| 83 | typeCounts[el.type] = (typeCounts[el.type] ?? 0) + 1; |
| 84 | } |
| 85 | const typeStr = Object.entries(typeCounts) |
| 86 | .map(([t, count]) => `${count} ${t}`) |
| 87 | .join(", "); |
| 88 | |
| 89 | if (args.json) { |
| 90 | console.log( |
| 91 | JSON.stringify( |
| 92 | withMeta({ |
| 93 | name: project.name, |
| 94 | resolution: orientation(width, height), |
| 95 | width, |
| 96 | height, |
| 97 | duration, |
| 98 | elements: parsed.elements.length, |
| 99 | tracks: tracks.size, |
| 100 | types: typeCounts, |
| 101 | size, |
| 102 | }), |
| 103 | null, |
| 104 | 2, |
| 105 | ), |
| 106 | ); |
| 107 | return; |
| 108 | } |
| 109 | |
| 110 | console.log(`${c.success("◇")} ${c.accent(project.name)}`); |
| 111 | console.log(label("Resolution", resolution)); |
| 112 | console.log(label("Duration", `${duration.toFixed(1)}s`)); |
nothing calls this directly
no test coverage detected