From 0e1c7cd8ed1bea00e9063b6e11ca602f49342ba7 Mon Sep 17 00:00:00 2001 From: venashial Date: Fri, 29 Jul 2022 13:44:34 -0700 Subject: [PATCH] Add landing page data for statistics & contributors --- src/plugins/generator/fetch.js | 2 +- src/plugins/generator/outputs/landingPage.js | 95 ++++++++++++++++++-- src/utils/ago.ts | 2 +- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/plugins/generator/fetch.js b/src/plugins/generator/fetch.js index 55dcb3c93..fd1d03fbb 100644 --- a/src/plugins/generator/fetch.js +++ b/src/plugins/generator/fetch.js @@ -12,7 +12,7 @@ export async function fetch(route, options = {}) { if (!version) { version = JSON.parse(await fs.readFile('./package.json', 'utf8')).version } - return baseFetch(API_URL + route, { + return baseFetch((route.startsWith('http') ? '' : API_URL) + route, { ...options, headers: { 'user-agent': `Omorphia / ${version} (venashial@modrinth.com)`, diff --git a/src/plugins/generator/outputs/landingPage.js b/src/plugins/generator/outputs/landingPage.js index 886e2b6d2..6a25c7a8c 100644 --- a/src/plugins/generator/outputs/landingPage.js +++ b/src/plugins/generator/outputs/landingPage.js @@ -4,18 +4,19 @@ import cliProgress from 'cli-progress' export async function landingPage() { const progressBar = new cliProgress.SingleBar({ - format: 'Generating landing page | {bar} | {percentage}% || {value}/{total} mods', + format: 'Generating landing page | {bar} | {percentage}%', barCompleteChar: '\u2588', barIncompleteChar: '\u2591', hideCursor: true, }) - progressBar.start(100, 0) + progressBar.start(111, 0) + /* MOD STACKS */ // Fetch top 100 mods - const response = await (await fetch('search?limit=100&facets=[["project_type:mod"]]')).json() + const mods = await (await fetch('search?limit=100&facets=[["project_type:mod"]]')).json() // Simplified array with the format: ['id', 'slug', 'icon_extension'] - const compressed = response.hits + const compressedMods = mods.hits .filter((project) => project.icon_url) .map((project) => { progressBar.increment() @@ -26,12 +27,94 @@ export async function landingPage() { ] }) + /* STATISTICS */ + const statistics = { + downloads: 0, + projects: 0, + authors: 0, + } + + // Get total number of projects + const projectCount = (await (await fetch('search?limit=0')).json()).total_hits + statistics.projects = projectCount + progressBar.increment() + + const authors = new Set() + + // Number of pages through search to fetch + const requestCount = Math.ceil(projectCount / 100) + await Promise.allSettled( + Array.from({ length: requestCount }, async (_, index) => { + const response = await fetch(`search?limit=100&offset=${index * 100}`) + if (!response.ok) { + throw new Error(`Failed to fetch projects: ${response.statusText}`) + } + // Get project hits & use map to get rid of extra data + const { hits } = await response.json() + + for (const hit of hits) { + authors.add(hit.author) + statistics.downloads += hit.downloads + } + }) + ) + + statistics.authors = authors.size + progressBar.increment() + + /* CONTRIBUTORS */ + const contributorCounts = new Map() + + const repoNames = [ + 'knossos', + 'labrinth', + 'theseus', + 'minotaur', + 'hydra', + 'daedalus', + 'omorphia', + 'sisyphus', + 'ariadne', + ] + + const repos = await Promise.all( + repoNames.map(async (repo) => { + const response = await fetch(`https://api.github.com/repos/modrinth/${repo}/contributors`) + + if (!response.ok) { + console.error(await response.json()) + throw new Error('Could not fetch repository from GitHub') + } + + progressBar.increment() + + return await response.json() + }) + ) + + for (const repo of repos) { + for (const user of repo) { + if (!user.login.includes('[bot]')) { + contributorCounts.set(user.login, { + avatar_url: user.avatar_url, + contributions: + (contributorCounts.get(user.login)?.contributions || 0) + user.contributions, + }) + } + } + } + + const contributors = Array.from(contributorCounts, ([name, data]) => ({ name, ...data })).sort( + (a, b) => b.contributions - a.contributions + ) + // Write JSON file await fs.writeFile( './generated/landingPage.json', JSON.stringify({ - mods: compressed, - random: Math.random(), + mods: compressedMods, + statistics, + contributors, }) ) progressBar.stop() diff --git a/src/utils/ago.ts b/src/utils/ago.ts index 8e780800a..902586a5a 100644 --- a/src/utils/ago.ts +++ b/src/utils/ago.ts @@ -4,7 +4,7 @@ */ const rft = new Intl.RelativeTimeFormat( - typeof navigator !== 'undefined' ? [...navigator.languages] : ['en'], + typeof navigator !== 'undefined' ? [...navigator?.languages] : ['en'], { numeric: 'auto' } )