Update utilities and documentation

This commit is contained in:
venashial
2022-05-20 19:53:13 -07:00
parent d8b59925b0
commit 8bf90714da
26 changed files with 6974 additions and 5236 deletions

View File

@@ -0,0 +1,10 @@
export default function Generator(options: PluginOptions): {
name: string;
buildStart(): Promise<void>;
};
export interface PluginOptions {
projectColors: boolean;
landingPage: boolean;
gameVersions: boolean;
tags: boolean;
}

View File

@@ -12,18 +12,16 @@ process.env.VITE_API_URL || process.env?.NODE_ENV === 'development'
// Time to live: 7 days
const TTL = 7 * 24 * 60 * 60 * 1000;
export default function Generator(options: PluginOptions) {
export default function Generator(options) {
return {
name: 'rollup-plugin-omorphia-generator',
async buildStart() {
let state: State = {};
let state = {};
try {
state = JSON.parse(await fs.readFile('./generated/state.json', 'utf8'));
} catch {
// File doesn't exist, create folder
await fs.mkdir('./generated', { recursive: true });
await fs.writeFile(
'./generated/state.json',
JSON.stringify(
@@ -35,7 +33,6 @@ export default function Generator(options: PluginOptions) {
)
);
}
// Don't generate if the last generation was less than TTL and the options are the same
if (
state?.lastGenerated &&
@@ -44,12 +41,10 @@ export default function Generator(options: PluginOptions) {
) {
return;
}
if (options.landingPage) await landingPage(API_URL);
if (options.projectColors) await projectColors(API_URL);
if (options.gameVersions) await gameVersions(API_URL);
if (options.tags) await tags(API_URL);
// Write new state
state.lastGenerated = new Date().toISOString();
state.options = options;
@@ -57,15 +52,3 @@ export default function Generator(options: PluginOptions) {
},
};
}
export interface PluginOptions {
projectColors: boolean;
landingPage: boolean;
gameVersions: boolean;
tags: boolean;
}
interface State {
lastGenerated?: string;
options?: PluginOptions;
}

View File

@@ -0,0 +1 @@
export declare function gameVersions(API_URL: string): Promise<void>;

View File

@@ -2,18 +2,16 @@ import { fetch } from 'undici';
import { promises as fs } from 'fs';
import cliProgress from 'cli-progress';
export async function gameVersions(API_URL: string) {
export async function gameVersions(API_URL) {
const progressBar = new cliProgress.SingleBar({
format: 'Generating game versions | {bar} | {percentage}%',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true,
});
progressBar.start(2, 0);
const gameVersions = await (await fetch(API_URL + 'tag/game_version')).json();
progressBar.increment();
// Write JSON file

View File

@@ -0,0 +1 @@
export declare function landingPage(API_URL: string): Promise<void>;

View File

@@ -2,20 +2,19 @@ import { fetch } from 'undici';
import { promises as fs } from 'fs';
import cliProgress from 'cli-progress';
export async function landingPage(API_URL: string) {
export async function landingPage(API_URL) {
const progressBar = new cliProgress.SingleBar({
format: 'Generating landing page | {bar} | {percentage}% || {value}/{total} mods',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true,
});
progressBar.start(100, 0);
// Fetch top 100 mods
const response = (await (
const response = await (
await fetch(API_URL + 'search?limit=100&facets=[["project_type:mod"]]')
).json()) as Record<string, any>;
).json();
// Simplified array with the format: ['id', 'slug', 'icon_extension']
const compressed = response.hits
@@ -37,6 +36,5 @@ export async function landingPage(API_URL: string) {
random: Math.random(),
})
);
progressBar.stop();
}

View File

@@ -0,0 +1 @@
export declare function projectColors(API_URL: string): Promise<void>;

View File

@@ -5,30 +5,21 @@ import Jimp from 'jimp';
import { getAverageColor } from 'fast-average-color-node';
// Note: This function has issues and will occasionally fail with some project icons. It averages at a 99.4% success rate. Most issues are from ECONNRESET errors & Jimp not being able to handle webp & svg images.
export async function projectColors(API_URL: string) {
export async function projectColors(API_URL) {
const progressBar = new cliProgress.SingleBar({
format: 'Generating project colors | {bar} | {percentage}% || {value}/{total} projects',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true,
});
// Get total number of projects
const projectCount = (
(await (await fetch(API_URL + 'search?limit=0')).json()) as Record<string, any>
).total_hits;
const projectCount = (await (await fetch(API_URL + 'search?limit=0')).json()).total_hits;
progressBar.start(projectCount, 0);
const writeStream = createWriteStream('./generated/projects.json');
writeStream.write('{');
// Used to form the JSON string (so that the first doesn't have a comma prefix)
let first = true;
let completed = 0;
// Number of pages through search to fetch
const requestCount = Math.ceil(projectCount / 100);
await Promise.allSettled(
@@ -37,15 +28,13 @@ export async function projectColors(API_URL: string) {
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()) as Record<string, any>).hits.map((project) => ({
const hits = (await response.json()).hits.map((project) => ({
project_id: project.project_id,
slug: project.slug,
title: project.title,
icon_url: project.icon_url,
}));
// Try parsing the icon of each project
await Promise.allSettled(
hits.map(async (project) => {
@@ -59,32 +48,25 @@ export async function projectColors(API_URL: string) {
const image = await Jimp.read(
project.icon_url.replace('cdn', 'cdn-raw') // Skip redirect to raw CDN
);
// Resize image before getting average color (faster)
image.resize(256, 256);
// Get bottom edge of image
const edge = image.clone().crop(0, 255, 256, 1);
const buffer = await edge.getBufferAsync(Jimp.AUTO);
let color = (await getAverageColor(buffer)).hexa;
// If the edge is transparent, use the average color of the entire image
if (color === '#00000000') {
const buffer = await image.getBufferAsync(Jimp.AUTO);
color = (await getAverageColor(buffer)).hexa;
}
// Remove color transparency
color = color.replace(/.{2}$/, '');
// Only use comma prefix if not first
let prefix = ',';
if (first) {
prefix = '';
first = false;
}
writeStream.write(`${prefix}"${project.project_id}":"${color}"`);
completed++;
} catch (error) {
@@ -97,10 +79,8 @@ export async function projectColors(API_URL: string) {
);
})
);
writeStream.write('}');
writeStream.end();
progressBar.stop();
console.log(`Failed to parse ${projectCount - completed} project icons.`);
}

View File

@@ -0,0 +1 @@
export declare function tags(API_URL: string): Promise<void>;

View File

@@ -1,31 +1,27 @@
import { fetch } from 'undici';
import { promises as fs } from 'fs';
import cliProgress from 'cli-progress';
export async function tags(API_URL: string) {
export async function tags(API_URL) {
const progressBar = new cliProgress.SingleBar({
format: 'Generating tags | {bar} | {percentage}%',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true,
});
progressBar.start(7, 0);
// eslint-disable-next-line prefer-const
let [categories, loaders, licenses, donationPlatforms]: any = await Promise.all([
let [categories, loaders, licenses, donationPlatforms] = await Promise.all([
await (await fetch(API_URL + 'tag/category')).json(),
await (await fetch(API_URL + 'tag/loader')).json(),
await (await fetch(API_URL + 'tag/license')).json(),
await (await fetch(API_URL + 'tag/donation_platform')).json(),
]);
progressBar.update(4);
// Delete icons from original arrays
categories = categories.map(({ icon, ...rest }) => rest);
loaders = loaders.map(({ icon, ...rest }) => rest);
progressBar.increment();
// Create single object with icons
@@ -33,7 +29,6 @@ export async function tags(API_URL: string) {
...categories.reduce((a, v) => ({ ...a, [v.name]: v.icon }), {}),
...loaders.reduce((a, v) => ({ ...a, [v.name]: v.icon }), {}),
};
progressBar.increment();
// Set project types