mirror of
https://github.com/citra-emu/discord-bot.git
synced 2024-12-22 19:36:07 +00:00
Add game DB lookup support (#32)
* Add game DB lookup support * Fix compatibility typo * Fix typo 2 * Use async function in game DB listing, avoid redundant HTTP requests
This commit is contained in:
parent
9d15288d9c
commit
b914780a65
13
env.json
13
env.json
|
@ -41,5 +41,18 @@
|
|||
"GITHUB_OLD_THRESHOLD": {
|
||||
"required": false,
|
||||
"description": "Issues below this treshold should be ignored"
|
||||
},
|
||||
"COMPAT_DB_SOURCE": {
|
||||
"description": "URL to pull game compatibility information from"
|
||||
},
|
||||
"COMPAT_DB_REFRESH": {
|
||||
"required": false,
|
||||
"description": "Minimum time in milliseconds between compatibility DB refreshes (default 20 minutes)"
|
||||
},
|
||||
"COMPAT_ICON_BASE": {
|
||||
"description": "URL (with trailing slash) to directory with <game-id>.png files"
|
||||
},
|
||||
"COMPAT_URL_BASE": {
|
||||
"description": "URL (with trailing slash) to directory with game information pages"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
"logdna": "^1.2.3",
|
||||
"node-schedule": "^1.2.3",
|
||||
"request": "^2.79.0",
|
||||
"request-promise-native": "^1.0.5",
|
||||
"string-similarity": "^1.2.0",
|
||||
"winston": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
94
src/commands/game.js
Normal file
94
src/commands/game.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
const request = require('request-promise-native');
|
||||
const discord = require('discord.js');
|
||||
const stringSimilarity = require('string-similarity');
|
||||
|
||||
const logger = require('../logging.js');
|
||||
const state = require('../state.js');
|
||||
|
||||
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 = {
|
||||
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": "black", "description": "The game has not yet been tested." }
|
||||
};
|
||||
|
||||
async function updateDatabase() {
|
||||
let body;
|
||||
try {
|
||||
body = await request(targetServer);
|
||||
} catch (e) {
|
||||
logger.error("Unable to download latest games list!");
|
||||
throw e;
|
||||
}
|
||||
|
||||
state.gameDB = JSON.parse(body);
|
||||
state.lastGameDBUpdate = Date.now();
|
||||
logger.info(`Updated games list (${state.gameDB.length} games)`);
|
||||
|
||||
state.gameDBPromise = null;
|
||||
}
|
||||
|
||||
exports.command = async function (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 == null) {
|
||||
state.gameDBPromise = updateDatabase(message);
|
||||
}
|
||||
|
||||
try {
|
||||
await state.gameDBPromise;
|
||||
} catch (e) {
|
||||
message.channel.send("Game compatibility feed temporarily unavailable - sorry!");
|
||||
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 = undefined;
|
||||
let bestScore = 0.5; // Game names must have at least a 50% similarity to be matched
|
||||
|
||||
state.gameDB.forEach(testGame => {
|
||||
const newDistance = stringSimilarity.compareTwoStrings(game.toLowerCase(), testGame.title.toLowerCase());
|
||||
if (newDistance > bestScore) {
|
||||
bestGame = testGame;
|
||||
bestScore = newDistance;
|
||||
}
|
||||
});
|
||||
|
||||
if (bestGame === undefined) {
|
||||
message.channel.send("Game could not be found.");
|
||||
return;
|
||||
}
|
||||
|
||||
const screenshot = `${iconBase}${bestGame.id}.png`;
|
||||
const url = `${urlBase}${bestGame.id}/`;
|
||||
|
||||
const compat = compatStrings[bestGame.compatibility];
|
||||
|
||||
const embed = new discord.RichEmbed()
|
||||
.addField("Status", compat.name, true)
|
||||
.addField("Needs System Files", bestGame.needs_system_files ? "Yes" : "No", true)
|
||||
.addField("Needs Shared Font", bestGame.needs_shared_font ? "Yes" : "No", true)
|
||||
.setTitle(bestGame.title)
|
||||
.setColor(compat.color)
|
||||
.setDescription(bestGame.description)
|
||||
.setURL(url)
|
||||
.setThumbnail(screenshot);
|
||||
|
||||
message.channel.send(embed);
|
||||
};
|
|
@ -11,6 +11,9 @@ var State = function () {
|
|||
leaves: 0,
|
||||
warnings: 0
|
||||
};
|
||||
this.lastGameDBUpdate = 0;
|
||||
this.gameDB = [];
|
||||
this.gameDBPromise = null;
|
||||
};
|
||||
|
||||
module.exports = new State();
|
||||
|
|
Loading…
Reference in a new issue