109 lines
4.1 KiB
TypeScript
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]});
|
|
}
|