#!/usr/bin/env nodejsscript /* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */ const instances_cz_pre= new Set([ "mastodonczech.cz", "mastodon.arch-linux.cz", "nasface.cz", "witter.cz", "cztwitter.cz", "mastodon.pirati.cz", "gomastodon.cz", "f.cz", "toot.whatever.cz", "mastodon.macsnet.cz", "lgbtcz.social", "kompost.cz", "boskovice.social", "propulse.club", "mastodon.1984.cz", "mastodon.rozhlas.cz", "fediverse.cz", "mastodon.queerclub.cz", "mastodon.urbancloud.cz", "kocour.club", "mastodon.telekomunikace.cz", "ajtaci.club", "mastodon.darksheep.social", "social.filik.eu", "social.meyer.cz", "mastodon.posvic.cz", "mastodon.starnet.cz", "blogator.com", "hatedon.1984.cz", "mastodon.loutaci.cz", "social.gwei.cz", "mastodon.vyboh.net", "mastodon.skorpil.cz", "mastodon.hinata.cz", "social.toxwat.cz", "spondr.cz", "hlidacstatu.social", "mastodon.train.cz", "social.bobek.cz", "social.blep.cz", "mastodon.kickme.cz", "mastodon.starlink.cz", "mastodon.kiklhorn.cz", "mastodon.haxo.cz", "mutant.cz", "masto.den1.cz", "mastodon.gmb.cz", "rodina-sucha.cz", "social.taborsky.cz", ]); const timeOut= (l= 500)=> AbortSignal.timeout(l); (async function main(){ let stats= []; for(const instance of instances_cz_pre){ echo.use("-R", "Shromažďuji instance: " + instance); const peers= await fetch("https://"+instance+"/api/v1/instance/peers", { signal: timeOut() }) .then(res=> res.json()).catch(()=> []); if(peers && Array.isArray(peers)) peers.filter(i=> i.endsWith(".cz")).forEach(i=> instances_cz_pre.add(i)); } const instances_cz= Array.from(instances_cz_pre); const { length }= instances_cz; for await(const data of collectStats(instances_cz, 4)){ echo.use("-R", "Shromažďuji data za instance: " + instances_cz.indexOf(data.instance)+"/"+length+": "+data.instance); stats.push(data); } const out= { instances_cz: stats.sort((a, b)=> b.registrations-a.registrations), sum: stats.reduce((acc, stats) => sumStats([acc, stats]), { statuses: 0, logins: 0, registrations: 0, mau: 0, user_count: 0 }) }; echo(JSON.stringify(out, null, " ")).to("./mastodonCzStats.json"); $.exit(0); })(); async function* collectStats(instances, weeks = 1) { for(const instance of instances){ const { stats, mau, user_count }= await fetchInstanceStats(instance).catch(e=> ({})); if(!stats || !Array.isArray(stats)) continue; yield { instance, mau, user_count, ...sumStats(stats.slice(0, weeks + 1)) }; } } function sumStats(arr) { const out= Object.keys(arr[0]).reduce((acc, curr)=> (acc[curr]= 0, acc), {}); for (const key of Object.keys(out)) for (const s of arr) out[key]+= Number(s[key]); return out; } async function fetchInstanceStats(instance) { const url_main= "https://" + instance + "/api/"; const stats= await fetch(url_main+"v1/instance/activity", { signal: timeOut() }).then(res=> res.json()); const { usage: { users } }= await fetch(url_main+"v2/instance", { signal: timeOut() }).then(res=> res.json()); const { stats: { user_count } }= await fetch(url_main+"v1/instance", { signal: timeOut() }).then(res=> res.json()); return { instance, stats, mau: users.active_month, user_count }; }