const needle = require("needle");
const userAgent = "xc-stats;
[email protected]";
const getJSON = ((url, gh) => {
let headers = { "User-Agent": userAgent };
if (!!gh) {
headers["Accept"] = "application/vnd.github+json";
headers["X-GitHub-Api-Version"] = "2022-11-28";
}
return needle("get", url, {
json: true,
headers: headers
}).then((res) => res.body);
});
// type Stats = { downloads: number, stars: number }
async function getStatsHangar() {
const body = await getJSON("https://hangar.papermc.io/api/v1/projects/XClaim");
let { downloads, stars } = body["stats"];
if (typeof downloads !== "number") downloads = parseInt(downloads);
if (typeof stars !== "number") stars = parseInt(stars);
return { downloads, stars };
}
async function getStatsSpigot() {
const body = await getJSON("https://api.spiget.org/v2/resources/102843");
let { downloads, reviews } = body;
if (typeof downloads !== "number") downloads = parseInt(downloads);
let stars = 0;
let len;
if (Array.isArray(reviews) && (len = Math.min(reviews.length, 100)) > 0) {
const detail = await getJSON("https://api.spiget.org/v2/resources/102843/reviews?size=" + len + "&page=0&fields=rating")
for (let i=0; i < detail.length; i++) {
stars += detail[i]["rating"]["average"];
}
stars /= detail.length;
}
return { downloads, stars };
}
const JAR_MIME_TYPES = { "application/x-java-archive": true, "application/java-archive": true };
async function getStatsGithub() {
// I sure would prefer to not use the search API for this. Whatever.
const body = await getJSON("https://api.github.com/search/repositories?q=WasabiThumb%2Fxclaim");
const item = body["items"][0];
let stars = item["stargazers_count"];
if (typeof stars !== "number") stars = parseInt(stars);
const releasesBody = await getJSON("https://api.github.com/repos/WasabiThumb/xclaim/releases");
let downloads = 0;
for (let i=0; i < releasesBody.length; i++) {
let assets = releasesBody[i]["assets"];
if (!Array.isArray(assets)) continue;
for (let asset of assets) {
if (!JAR_MIME_TYPES[asset["content_type"]]) continue;
let name = asset["name"];
if (typeof name !== "string") continue;
if (name.startsWith("original")) continue;
downloads += parseInt(asset["download_count"]);
}
}
return { downloads, stars };
}
const statFunctions = [ getStatsSpigot, getStatsGithub, getStatsHangar ];
async function getStats() {
let promises = new Array(statFunctions.length);
for (let i=0; i < statFunctions.length; i++) {
promises[i] = statFunctions[i]();
}
let totalDownloads = 0;
let totalStars = 0;
const data = await Promise.allSettled(promises);
for (let entry of data) {
if (entry.status !== "fulfilled") continue;
let { downloads, stars } = entry.value;
if (!isNaN(downloads)) totalDownloads += downloads;
if (!isNaN(stars)) totalStars += stars;
}
return { downloads: totalDownloads, stars: Math.round(totalStars) };
}
exports.endpoint = async function (request, response) {
let key = "Downloads";
if (request.url.toLowerCase().indexOf("stars") !== -1) key = "Stars";
const data = await getStats();
const metric = data[key.toLowerCase()];
response.end(JSON.stringify({
"schemaVersion": 1,
"label": key,
"message": metric.toString(),
"color": "informational"
}));
}