|
1 | 1 | import fetch from "node-fetch";
|
2 |
| -import * as cheerio from "cheerio"; |
3 | 2 | import { formatParams, Options } from "./formatParams";
|
4 | 3 |
|
5 | 4 | /**
|
@@ -40,72 +39,37 @@ export const getGithubUserContribution = async (
|
40 | 39 | };
|
41 | 40 |
|
42 | 41 | const parseUserPage = (content: string) => {
|
43 |
| - const $ = cheerio.load(content); |
44 |
| - |
45 |
| - // |
46 |
| - // parse cells |
47 |
| - const rawCells = $(".js-calendar-graph rect[data-count]") |
48 |
| - .toArray() |
49 |
| - .map((x) => { |
50 |
| - const level = +x.attribs["data-level"]; |
51 |
| - const count = +x.attribs["data-count"]; |
52 |
| - const date = x.attribs["data-date"]; |
53 |
| - |
54 |
| - return { |
55 |
| - svgPosition: getSvgPosition(x), |
56 |
| - level, |
57 |
| - count, |
58 |
| - date, |
59 |
| - }; |
60 |
| - }); |
61 |
| - |
62 |
| - const xMap: Record<number, true> = {}; |
63 |
| - const yMap: Record<number, true> = {}; |
64 |
| - rawCells.forEach(({ svgPosition: { x, y } }) => { |
65 |
| - xMap[x] = true; |
66 |
| - yMap[y] = true; |
67 |
| - }); |
| 42 | + // take roughly the svg block |
| 43 | + const block = content |
| 44 | + .split(`class="js-calendar-graph-svg"`)[1] |
| 45 | + .split("</svg>")[0]; |
68 | 46 |
|
69 |
| - const xRange = Object.keys(xMap) |
70 |
| - .map((x) => +x) |
71 |
| - .sort((a, b) => +a - +b); |
72 |
| - const yRange = Object.keys(yMap) |
73 |
| - .map((x) => +x) |
74 |
| - .sort((a, b) => +a - +b); |
| 47 | + let x = 0; |
| 48 | + let lastYAttribute = 0; |
75 | 49 |
|
76 |
| - const cells = rawCells.map(({ svgPosition, ...c }) => ({ |
77 |
| - ...c, |
78 |
| - x: xRange.indexOf(svgPosition.x), |
79 |
| - y: yRange.indexOf(svgPosition.y), |
80 |
| - })); |
81 |
| - |
82 |
| - return cells; |
83 |
| -}; |
| 50 | + const rects = Array.from(block.matchAll(/<rect[^>]*>/g)).map(([m]) => { |
| 51 | + const date = m.match(/data-date="([^"]+)"/)![1]; |
| 52 | + const count = +m.match(/data-count="([^"]+)"/)![1]; |
| 53 | + const level = +m.match(/data-level="([^"]+)"/)![1]; |
| 54 | + const yAttribute = +m.match(/y="([^"]+)"/)![1]; |
84 | 55 |
|
85 |
| -// returns the position of the svg elements, accounting for it's transform and it's parent transform |
86 |
| -// ( only accounts for translate transform ) |
87 |
| -const getSvgPosition = ( |
88 |
| - e: cheerio.Element | null |
89 |
| -): { x: number; y: number } => { |
90 |
| - if (!e || e.tagName === "svg") return { x: 0, y: 0 }; |
| 56 | + if (lastYAttribute > yAttribute) x++; |
91 | 57 |
|
92 |
| - const p = getSvgPosition(e.parent as cheerio.Element); |
| 58 | + lastYAttribute = yAttribute; |
93 | 59 |
|
94 |
| - if (e.attribs.x) p.x += +e.attribs.x; |
95 |
| - if (e.attribs.y) p.y += +e.attribs.y; |
| 60 | + return { date, count, level, x, yAttribute }; |
| 61 | + }); |
96 | 62 |
|
97 |
| - if (e.attribs.transform) { |
98 |
| - const m = e.attribs.transform.match( |
99 |
| - /translate\( *([\.\d]+) *, *([\.\d]+) *\)/ |
100 |
| - ); |
| 63 | + const yAttributes = Array.from( |
| 64 | + new Set(rects.map((c) => c.yAttribute)).keys() |
| 65 | + ).sort(); |
101 | 66 |
|
102 |
| - if (m) { |
103 |
| - p.x += +m[1]; |
104 |
| - p.y += +m[2]; |
105 |
| - } |
106 |
| - } |
| 67 | + const cells = rects.map(({ yAttribute, ...c }) => ({ |
| 68 | + y: yAttributes.indexOf(yAttribute), |
| 69 | + ...c, |
| 70 | + })); |
107 | 71 |
|
108 |
| - return p; |
| 72 | + return cells; |
109 | 73 | };
|
110 | 74 |
|
111 | 75 | export type Res = Awaited<ReturnType<typeof getGithubUserContribution>>;
|
|
0 commit comments