From ac392bd0d4d1a2f4ef6f0b8797d5c0adaaf07d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81sgeir=20Thor=20Johnson?= Date: Fri, 19 Jun 2026 00:14:57 +0000 Subject: [PATCH] Add live stars today/7d/30d readout to the GitHub Stars card Fetch real stars gained in rolling 1d/7d/30d windows from live starredAt timestamps (GraphQL, newest-first) at generation time, so the readout matches GitHub's own numbers regardless of snapshot timing. Falls back to the daily series if the fetch fails. Stat card 7d now sourced the same way. --- .github/scripts/accumulate-traffic.py | 80 +++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/.github/scripts/accumulate-traffic.py b/.github/scripts/accumulate-traffic.py index 3edff9d..86c30e3 100644 --- a/.github/scripts/accumulate-traffic.py +++ b/.github/scripts/accumulate-traffic.py @@ -92,6 +92,44 @@ def fetch_star_count(): print(f"Star fetch failed: {e}") return None +def fetch_star_windows(): + """Real stars gained in rolling 1d / 7d / 30d windows, counted from live + starredAt timestamps (GraphQL, newest-first). Matches GitHub's own numbers + and is independent of snapshot timing. Returns None on failure.""" + token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") + if not token: + return None + now = datetime.now(timezone.utc) + bounds = {"d1": now.timestamp() - 86400, "d7": now.timestamp() - 7*86400, "d30": now.timestamp() - 30*86400} + counts = {"d1": 0, "d7": 0, "d30": 0} + cursor, pages = None, 0 + try: + while pages < 60: + after = f', after: "{cursor}"' if cursor else '' + query = ('{ repository(owner:"asgeirtj", name:"system_prompts_leaks"){ stargazers(first:100%s, ' + 'orderBy:{field:STARRED_AT, direction:DESC}){ pageInfo{endCursor hasNextPage} edges{starredAt} } } }') % after + body = json.dumps({"query": query}).encode() + req = urllib.request.Request("https://api.github.com/graphql", data=body, + headers={"Authorization": f"Bearer {token}", "User-Agent": "traffic-dashboard", "Content-Type": "application/json"}) + with urllib.request.urlopen(req, timeout=30) as r: + s = json.load(r)["data"]["repository"]["stargazers"] + oldest = now.timestamp() + for e in s["edges"]: + t = datetime.fromisoformat(e["starredAt"].replace("Z", "+00:00")).timestamp() + oldest = t + for k, b in bounds.items(): + if t >= b: + counts[k] += 1 + pages += 1 + if oldest < bounds["d30"] or not s["pageInfo"]["hasNextPage"]: + break + cursor = s["pageInfo"]["endCursor"] + print(f"Star windows: today={counts['d1']} 7d={counts['d7']} 30d={counts['d30']} ({pages} pages)") + return counts + except Exception as e: + print(f"Star windows fetch failed: {e}") + return None + def accumulate_stars(publish_dir): today = datetime.now(timezone.utc).strftime("%Y-%m-%d") data_dir = os.path.join(publish_dir, TRAFFIC_DIR) @@ -115,9 +153,9 @@ def accumulate_stars(publish_dir): json.dump(star_history, f, separators=(",", ":")) print(f"Accumulated: {len(star_history)} star snapshots (latest={star_history[-1]['stars'] if star_history else 'n/a'})") - return star_history + return star_history, fetch_star_windows() -def build_dashboard(publish_dir, ref_history, path_history, star_history): +def build_dashboard(publish_dir, ref_history, path_history, star_history, star_windows): data_dir = os.path.join(publish_dir, TRAFFIC_DIR) views = load_json(os.path.join(data_dir, "traffic_views.json")) clones = load_json(os.path.join(data_dir, "traffic_clones.json")) @@ -132,6 +170,7 @@ def build_dashboard(publish_dir, ref_history, path_history, star_history): "referrer_series": ref_history, "paths_series": path_history, "stars_series": star_history, + "stars_windows": star_windows, }, separators=(",", ":")) html = DASHBOARD_TEMPLATE.replace("__DATA_PLACEHOLDER__", embedded) @@ -207,7 +246,7 @@ DASHBOARD_TEMPLATE = r"""

Traffic dashboard — auto-updated daily from the traffic branch

Daily Views

Drag to zoom — click Reset to restore

-
GitHub Stars (cumulative)

Bars show stars gained per day · drag to zoom

+
GitHub Stars (cumulative)

Bars show stars gained per day · drag to zoom

Page Trends — daily 14-day view count for the top pages

@@ -259,14 +298,35 @@ const curStars = starSeries.length ? starSeries[starSeries.length-1].stars : nul // 40k-stargazer cap, so early on there's a multi-week gap before today's // point — label the gain by its TRUE span so it never claims "7d" for a // 36-day delta. Self-heals to "7d" once daily points fill in. -let starGain = null, starGainDays = 0; -if (starSeries.length > 1) { +// gain over the trailing N days: find the snapshot ~N days back and subtract. +// Returns {gain, days} where days is the TRUE span covered (so it never claims +// "7d" for a wider gap left by the one-time 40k-cap backfill seam). +function starGainOver(n) { + if (starSeries.length < 2) return null; const lastDate = new Date(starSeries[starSeries.length-1].date); - const cutoff = new Date(lastDate); cutoff.setDate(cutoff.getDate()-7); + const cutoff = new Date(lastDate); cutoff.setDate(cutoff.getDate()-n); let base = starSeries[0]; for (const p of starSeries) { if (new Date(p.date) <= cutoff) base = p; } - starGain = curStars - base.stars; - starGainDays = Math.round((lastDate - new Date(base.date)) / 86400000) || 1; + return { gain: curStars - base.stars, days: Math.round((lastDate - new Date(base.date)) / 86400000) || 1 }; +} +// Prefer live rolling-window counts (real starredAt timestamps, matches +// GitHub's own numbers); fall back to the daily series if that fetch failed. +const sw = DATA.stars_windows; +const g7s = starGainOver(7); +const starGain = sw ? sw.d7 : (g7s ? g7s.gain : null); +const starGainDays = 7; + +if (curStars != null) { + let parts; + if (sw) { + parts = [['today',sw.d1],['7d',sw.d7],['30d',sw.d30]]; + } else { + parts = [['today',starGainOver(1)?.gain],['7d',starGainOver(7)?.gain],['30d',starGainOver(30)?.gain]]; + } + document.getElementById('starReadout').innerHTML = parts + .filter(([,v])=>v!=null) + .map(([l,v])=>`${v>=0?'+':''}${fmt(v)} ${l}`) + .join('  ·  '); } const statCards = [ @@ -492,5 +552,5 @@ if __name__ == "__main__": publish_dir = sys.argv[1] print(f"Processing traffic data in {publish_dir}") ref_history, path_history = accumulate(publish_dir) - star_history = accumulate_stars(publish_dir) - build_dashboard(publish_dir, ref_history, path_history, star_history) + star_history, star_windows = accumulate_stars(publish_dir) + build_dashboard(publish_dir, ref_history, path_history, star_history, star_windows)