diff options
| author | Joe Mou <dev@mou.fo> | 2026-01-25 16:27:48 -0500 |
|---|---|---|
| committer | Joe Mou <dev@mou.fo> | 2026-01-25 17:46:15 -0500 |
| commit | 7132094f28ca2dc08c32f207ade9c63a28952115 (patch) | |
| tree | 103f64b974ea709e810832dcce5c0625ff55bc1c /src/scraper.ts | |
| parent | 27588cba68a2594da8a41d8d3ebaecaadb3ab2f2 (diff) | |
Repository page with info
Diffstat (limited to 'src/scraper.ts')
| -rw-r--r-- | src/scraper.ts | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/scraper.ts b/src/scraper.ts index d6702cc..a405139 100644 --- a/src/scraper.ts +++ b/src/scraper.ts @@ -37,6 +37,18 @@ export interface GitHubTree extends GitHubCommon { items: TreeItem[]; } +export interface RepoInfo { + description: string | null; + website: string | null; + stars: string | null; + watchers: string | null; + forks: string | null; +} + +export interface GitHubRepo extends GitHubTree { + info: RepoInfo; +} + export interface GitHubBlob extends GitHubCommon { language: string | null; size: number; @@ -84,6 +96,25 @@ function parsePayload( return null; } +function parseRepoInfo(html: string): RepoInfo { + const descMatch = html.match(/<p[^>]*class="[^"]*f4[^"]*"[^>]*>([\s\S]*?)<\/p>/); + const description = descMatch?.[1]?.replace(/<[^>]+>/g, "").trim() || null; + const websiteMatch = html.match( + /<a[^>]*rel="noopener noreferrer nofollow"[^>]*href="([^"]+)"/, + ); + const starsMatch = html.match(/id="repo-stars-counter-star"[^>]*>([^<]+)/); + const watchersMatch = html.match(/<strong>(\d+)<\/strong>\s*watching/); + const forksMatch = html.match(/id="repo-network-counter"[^>]*>([^<]+)/); + + return { + description, + website: websiteMatch?.[1] || null, + stars: starsMatch?.[1]?.trim() || null, + watchers: watchersMatch?.[1] || null, + forks: forksMatch?.[1]?.trim() || null, + }; +} + function extractGitHub<T>(payload: RawPayload, extra: T): GitHubCommon & T { return { repo: { @@ -96,6 +127,26 @@ function extractGitHub<T>(payload: RawPayload, extra: T): GitHubCommon & T { }; } +export async function getGitHubRepo( + owner: string, + repo: string, +): Promise<GitHubRepo> { + const html = await fetchGitHubPage(`${owner}/${repo}`); + + const payload = parsePayload(html, "react-partial.embeddedData", [ + "props", + "initialPayload", + ]); + + if (payload?.tree === undefined) { + throw new Error("Could not find tree data in embedded JSON"); + } + + const info = parseRepoInfo(html); + + return extractGitHub(payload, { items: payload.tree.items, info }); +} + export async function getGitHubTree( owner: string, repo: string, |
