2021-10-22 01:43:19 -06:00

109 lines
4.1 KiB
TypeScript

import fetch from 'node-fetch';
import discord = require('discord.js');
import stringSimilarity = require('string-similarity');
import logger from '../logging';
import state from '../state';
import { IGameDBEntry, ICompatList } from '../models/interfaces';
const targetServer = process.env.COMPAT_DB_SOURCE;
const refreshTime = process.env.COMPAT_REFRESH_TIME ? parseInt(process.env.COMPAT_REFRESH_TIME) : 1000 * 60 * 20;
const iconBase = process.env.COMPAT_ICON_BASE;
const urlBase = process.env.COMPAT_URL_BASE;
const compatStrings: ICompatList = {
0: { key: '0', name: 'Perfect', color: '#5c93ed', description: 'Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed.' },
1: { key: '1', name: 'Great', color: '#47d35c', description: 'Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.' },
2: { key: '2', name: 'Okay', color: '#94b242', description: 'Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.' },
3: { key: '3', name: 'Bad', color: '#f2d624', description: 'Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.' },
4: { key: '4', name: 'Intro/Menu', color: 'RED', description: 'Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.' },
5: { key: '5', name: "Won't Boot", color: '#828282', description: 'The game crashes when attempting to startup.' },
99: { key: '99', name: 'Not Tested', color: 'DARK_BUT_NOT_BLACK', description: 'The game has not yet been tested.' }
};
async function updateDatabase () {
let body: any;
if (!targetServer) {
logger.error('Unable to download latest games list!');
return;
}
try {
let response = await fetch(targetServer);
body = await response.json();
} catch (e) {
logger.error('Unable to download latest games list!');
throw e;
}
state.gameDB = body.map((x: IGameDBEntry) => {
return {
directory: x.directory,
title: x.title,
compatibility: x.compatibility
};
});
state.lastGameDBUpdate = Date.now();
logger.info(`Updated games list (${state.gameDB.length} games)`);
state.gameDBPromise = null;
}
export async function command (message: discord.Message) {
if (Date.now() - state.lastGameDBUpdate > refreshTime) {
// Update remote list of games locally.
const waitMessage = message.channel.send('This will take a second...');
if (!state.gameDBPromise) {
state.gameDBPromise = updateDatabase();
}
try {
await state.gameDBPromise;
} catch (e) {
message.channel.send('Game compatibility feed temporarily unavailable.');
throw e;
} finally {
// We don't need this message anymore
waitMessage.then(waitMessageResult => waitMessageResult.delete());
}
}
const game = message.content.substr(message.content.indexOf(' ') + 1);
// Search all games. This is only linear time, so /shrug?
let bestGame: IGameDBEntry | null = null;
let bestScore = 0.5; // Game names must have at least a 50% similarity to be matched
// for is faster than forEach
for (let index = 0; index < state.gameDB.length; index++) {
const testGame = state.gameDB[index];
const newDistance = stringSimilarity.compareTwoStrings(game.toLowerCase(), testGame.title.toLowerCase());
if (newDistance > bestScore) {
bestGame = testGame;
bestScore = newDistance;
}
}
if (!bestGame) {
message.channel.send('Game could not be found.');
return;
}
const screenshot = `${iconBase}${bestGame.directory}.png`;
const url = `${urlBase}${bestGame.directory}/`;
const compat = compatStrings[bestGame.compatibility];
const embed = new discord.MessageEmbed()
.addField('Status', compat.name, true)
.setTitle(bestGame.title)
.setColor(compat.color)
.setDescription(compat.description)
.setURL(url)
.setThumbnail(screenshot);
message.channel.send({embeds: [embed]});
}