blob: 68c72a5b5ac4f66ff7beeee930b35085dae2fd9d [file] [edit]
// Copyright (c) 2009 Giampaolo Rodola. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Fills in star count and latest version from the GitHub API. Results
// are cached in sessionStorage for an hour to avoid hitting the rate
// limit on every page navigation.
(function () {
const REPO = "giampaolo/psutil";
const CACHE_KEY = "psutil-gh-meta";
const CACHE_TTL_MS = 60 * 60 * 1000;
function applyValues(stars, version) {
const s = document.querySelector(".topbar-stars");
const v = document.querySelector(".topbar-version");
if (s && stars) {
s.textContent = stars;
}
if (v && version) {
v.textContent = version;
}
}
function formatStars(n) {
if (typeof n !== "number") {
return "";
}
if (n >= 1000) {
return (n / 1000).toFixed(1) + "k";
}
return String(n);
}
let cached;
try {
cached = JSON.parse(sessionStorage.getItem(CACHE_KEY) || "null");
} catch (e) {
cached = null;
}
if (cached && Date.now() - cached.t < CACHE_TTL_MS) {
applyValues(cached.stars, cached.version);
return;
}
Promise.all([
fetch("https://api.github.com/repos/" + REPO).then((r) => (r.ok ? r.json() : null)),
// /releases/latest only works if a release is explicitly
// marked as latest. /tags is more reliable.
fetch("https://api.github.com/repos/" + REPO + "/tags").then((r) => (r.ok ? r.json() : null)),
])
.then((results) => {
const repo = results[0];
const tags = results[1];
// Skip caching on a rate-limit / error response so the next
// page load retries instead of showing empty for an hour.
if (!repo || !Array.isArray(tags)) {
return;
}
const stars = formatStars(repo.stargazers_count);
const rawTag = (tags[0] && tags[0].name) || "";
// GitHub returns tags like "v7.2.2"; drop the leading "v"
// so the topbar shows the bare version number.
const version = rawTag.replace(/^v/, "");
try {
sessionStorage.setItem(
CACHE_KEY,
JSON.stringify({ t: Date.now(), stars: stars, version: version })
);
} catch (e) {
// private mode / storage disabled: skip caching
}
applyValues(stars, version);
})
.catch(() => {
// offline / network error: leave the topbar placeholders
});
})();