From b43ce92c7b16bdefedb7c4c2aef41f9417f1ddf6 Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Tue, 11 Aug 2026 08:09:47 -0400 Subject: Add language percentages to repo pages GitHub no longer server-renders the repository sidebar; its React UI lazily fetches /:owner/:repo/_sidebar as JSON, which carries the language breakdown (name, percentage, color). getGitHubLanguages() uses that endpoint, and a new /api/:owner/:repo/languages fragment route renders the bar and legend the same way refs and latest-commit already work, so repo page loads still cost a single scrape. The latest-commit placeholder loader in refs.js is generalized over .placeholder[data-src] so both placeholders share it. Co-Authored-By: Claude Opus 5 --- src/scraper.ts | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/scraper.ts') diff --git a/src/scraper.ts b/src/scraper.ts index 39ad2cd..223839f 100644 --- a/src/scraper.ts +++ b/src/scraper.ts @@ -285,6 +285,17 @@ export interface GitHubLatestCommit extends GitHubCommon { commit: LatestCommit; } +export interface Language { + // "Other" for the aggregate bucket GitHub reports without a name. + name: string; + percentage: number; + color: string | null; +} + +export interface GitHubLanguages extends GitHubCommon { + languages: Language[]; +} + export interface Ref { name: string; isDefault?: boolean; @@ -722,6 +733,34 @@ export async function getGitHubLatestCommit( }; } +interface SidebarPayload { + languages?: { + languages: { + // Absent for the "Other" bucket. + name?: string; + percentage: number; + color?: string; + }[]; + }; +} + +// The repository sidebar (languages, contributors, ...) is not rendered into +// the repo page at all; GitHub's own UI lazily fetches it as JSON from here. +export async function getGitHubLanguages(owner: string, repo: string): Promise { + const payload = await fetchGitHubJson(`${owner}/${repo}/_sidebar`); + + const languages: Language[] = []; + for (const entry of payload.languages?.languages ?? []) { + languages.push({ + name: entry.name ?? "Other", + percentage: entry.percentage, + color: entry.color ?? null, + }); + } + + return { repo: { owner, name: repo }, languages }; +} + interface BranchRefEntry { name: string; isDefault: boolean; -- cgit v1.3.1