Tried adding some heuristics to searching emotes

This commit is contained in:
WatDuhHekBro 2020-12-16 23:12:17 -06:00
parent 692fd2c164
commit 2017e45403
4 changed files with 53 additions and 29 deletions

View File

@ -10,5 +10,5 @@ module.exports = {
bracketSpacing: false,
jsxBracketSameLine: false,
arrowParens: "always",
endOfLine: "lf"
endOfLine: "auto" // Apparently, the GitHub repository still uses CRLF. I don't know how to force it to use LF, and until someone figures that out, I'm changing this to auto because I don't want more than one line ending commit.
};

View File

@ -1,19 +1,19 @@
import {MessageEmbed} from "discord.js";
import Command from "../../core/command";
import {CommonLibrary} from "../../core/lib";
import {queryClosestEmoteByName} from "./subcommands/emote-utils";
import {botHasPermission} from "../../core/lib";
import {Permissions} from "discord.js";
export default new Command({
description: "Send the specified emote.",
run: "Please provide a command name.",
any: new Command({
description: "The emote to send.",
usage: "<emote>",
async run($: CommonLibrary): Promise<any> {
const search = $.args[0].toLowerCase();
const emote = $.client.emojis.cache.find((emote) => emote.name.toLowerCase().includes(search));
if (!emote) return $.channel.send("That's not a valid emote name!");
$.message.delete();
$.channel.send(`${emote}`);
description: "The emote(s) to send.",
usage: "<emotes...>",
async run({guild, channel, message, args}) {
let output = "";
for (const query of args) output += queryClosestEmoteByName(query).toString();
if (botHasPermission(guild, Permissions.FLAGS.MANAGE_MESSAGES)) message.delete();
channel.send(output);
}
})
});

View File

@ -1,6 +1,7 @@
import Command from "../../core/command";
import {CommonLibrary} from "../../core/lib";
import {Message, Channel, TextChannel} from "discord.js";
import {queryClosestEmoteByName} from "./subcommands/emote-utils";
export default new Command({
description:
@ -94,26 +95,16 @@ export default new Command({
).last();
}
let anyEmoteIsValid = false;
for (const search of $.args) {
const emoji = $.client.emojis.cache.find((emoji) => emoji.name === search);
// Even though the bot will always grab *some* emote, the user can choose not to keep that emote there if it isn't what they want
const emote = queryClosestEmoteByName(search);
const reaction = await target!.react(emote);
if (emoji) {
// Call the delete function only once to avoid unnecessary errors.
if (!anyEmoteIsValid && distance !== 0) $.message.delete();
anyEmoteIsValid = true;
const reaction = await target?.react(emoji);
// This part is called with a promise because you don't want to wait 5 seconds between each reaction.
setTimeout(() => {
/// @ts-ignore
reaction.users.remove($.client.user);
}, 5000);
}
// This part is called with a promise because you don't want to wait 5 seconds between each reaction.
setTimeout(() => {
// This reason for this null assertion is that by the time you use this command, the client is going to be loaded.
reaction.users.remove($.client.user!);
}, 5000);
}
if (!anyEmoteIsValid && !$.message.deleted) $.message.react("❓");
}
});

View File

@ -0,0 +1,33 @@
import {client} from "../../../index";
// Calculate and match the list of emotes against the queried emote, then sort the IDs based on calculated priority.
export function queryClosestEmoteByName(query: string) {
const priorityTable: {[id: string]: number} = {};
for (const emote of client.emojis.cache.values()) priorityTable[emote.id] = compareEmoteNames(emote.name, query);
const resultingIDs = Object.keys(priorityTable).sort((a, b) => priorityTable[b] - priorityTable[a]);
return client.emojis.cache.get(resultingIDs[0])!;
}
// Compare an emote's name against a query to see how alike the two are. The higher the number, the closer they are. Takes into account length and capitalization.
function compareEmoteNames(emote: string, query: string) {
let likeness = -Math.abs(emote.length - query.length);
const isQueryLonger = query.length > emote.length;
// Loop through all indexes that the two strings share then compare each letter.
for (let i = 0; i < (isQueryLonger ? emote.length : query.length); i++) {
const c = emote[i];
const q = query[i];
// If they're the exact same character
if (c === q) likeness += 3;
// If the query is uppercase but the emote is lowercase
else if (c === q.toLowerCase()) likeness += 2;
// If the query is lowercase but the emote is uppercase
else if (c === q.toUpperCase()) likeness += 1;
// Otherwise, if they're different characters, don't add anything (this isn't a spellchecker)
}
return likeness;
}