354 lines
8.3 KiB
TypeScript
354 lines
8.3 KiB
TypeScript
import { MessageEmbed } from 'discord.js';
|
|
|
|
/* TYPES */
|
|
|
|
type basicObject = {[keys: string]: string};
|
|
|
|
type URL = string;
|
|
|
|
type bigString = string | string[];
|
|
interface embedData {
|
|
content?: string,
|
|
embeds: MessageEmbed[]
|
|
}
|
|
interface embedField {
|
|
name: string,
|
|
value: bigString,
|
|
inline?: boolean
|
|
}
|
|
|
|
interface authorData {
|
|
name: string,
|
|
url?: string,
|
|
icon?: string
|
|
}
|
|
interface footerData {
|
|
text: string,
|
|
icon?: string
|
|
}
|
|
interface embedObj {
|
|
embed: true,
|
|
|
|
content?: string,
|
|
title?: string,
|
|
description?: bigString,
|
|
url?: URL,
|
|
color?: string,
|
|
footer?: string | footerData,
|
|
thumbnail?: URL,
|
|
image?: URL,
|
|
author?: string | authorData,
|
|
fields?: embedField[],
|
|
timestamp?: boolean | string | number
|
|
}
|
|
|
|
type LangObj = { [keys:string]: LangObj | embedObj | string }
|
|
type LangObjWhole = { [langid:string]: LangObj }
|
|
|
|
/* UTIL FUNCS */
|
|
|
|
function template(str: string, args: basicObject): string {
|
|
|
|
return str.replace(/{\w+}/g, str => {
|
|
|
|
const key = str.substring(1, str.length-1);
|
|
|
|
if (key in args)
|
|
return args[key];
|
|
|
|
return key;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function bigString(str: bigString): string {
|
|
if (typeof str === 'object')
|
|
return str.join('\n');
|
|
return str;
|
|
}
|
|
|
|
function resolveColor(color: string): [number, number, number] {
|
|
color = color.replace(/[^0-9a-f]/gi, '');
|
|
|
|
const colorNum: [number, number, number] = [0, 0, 0];
|
|
|
|
if (color.length === 3 || color.length === 6) {
|
|
|
|
const colorSpl = /([0-9a-f]{1,2})([0-9a-f]{1,2})([0-9a-f]{1,2})/.exec(color);
|
|
|
|
if (!colorSpl)
|
|
return colorNum;
|
|
|
|
for (let i = 0; i < colorSpl.length && i < colorNum.length; i++)
|
|
colorNum[i] = parseInt(colorSpl[i], 16);
|
|
|
|
}
|
|
|
|
return colorNum;
|
|
}
|
|
|
|
function embedObjStr(embedData: embedObj, fallback = ''): string {
|
|
|
|
if (embedData.content !== undefined)
|
|
return bigString(embedData.content);
|
|
|
|
if (embedData.description !== undefined)
|
|
return bigString(embedData.description);
|
|
|
|
return fallback;
|
|
}
|
|
|
|
function embedObjEmbed(embedObj: embedObj, args: basicObject = {}): MessageEmbed {
|
|
const embed = new MessageEmbed(),
|
|
{ author, color, description, fields, footer, image, thumbnail, timestamp, title, url } = embedObj;
|
|
|
|
if (author !== undefined) {
|
|
|
|
let authorFix: authorData;
|
|
|
|
if (typeof author === 'string')
|
|
authorFix = {
|
|
name: template(author, args)
|
|
};
|
|
else {
|
|
|
|
const {name, icon, url} = author;
|
|
|
|
authorFix = {
|
|
name: template(name, args)
|
|
};
|
|
|
|
if (icon !== undefined)
|
|
authorFix.icon = template(icon, args);
|
|
|
|
if (url !== undefined)
|
|
authorFix.url = template(url, args);
|
|
|
|
}
|
|
|
|
embed.setAuthor(authorFix);
|
|
|
|
}
|
|
|
|
if (footer !== undefined) {
|
|
|
|
let footerFix: footerData;
|
|
|
|
if (typeof footer === 'string')
|
|
footerFix = {
|
|
text: template(footer, args)
|
|
};
|
|
else {
|
|
|
|
const {text, icon} = footer;
|
|
|
|
footerFix = {
|
|
text: template(text, args)
|
|
};
|
|
|
|
if (icon !== undefined)
|
|
footerFix.icon = template(icon, args);
|
|
|
|
}
|
|
|
|
embed.setFooter(footerFix);
|
|
|
|
}
|
|
|
|
if (color !== undefined)
|
|
embed.setColor(resolveColor(template(color, args)));
|
|
|
|
if (description !== undefined)
|
|
embed.setDescription(template(bigString(description), args));
|
|
|
|
if (image !== undefined)
|
|
embed.setImage(template(image, args));
|
|
|
|
if (thumbnail !== undefined)
|
|
embed.setThumbnail(template(thumbnail, args));
|
|
|
|
if (title !== undefined)
|
|
embed.setTitle(template(title, args));
|
|
|
|
if (url !== undefined)
|
|
embed.setURL(template(url, args));
|
|
|
|
if (timestamp === true)
|
|
embed.setTimestamp();
|
|
else if (typeof timestamp === 'string')
|
|
embed.setTimestamp(new Date(template(timestamp, args)));
|
|
else if (timestamp !== false)
|
|
embed.setTimestamp(timestamp);
|
|
|
|
fields?.forEach(field => {
|
|
embed.addField(template(field.name, args), template(bigString(field.value), args), field.inline);
|
|
});
|
|
|
|
return embed;
|
|
}
|
|
|
|
/* LANG */
|
|
|
|
|
|
|
|
const LANG: LangObjWhole = {
|
|
|
|
en: {
|
|
|
|
main: {
|
|
login: 'Logged in as {user}'
|
|
},
|
|
|
|
discord: {
|
|
botRestart: 'The bot has just restarted, anybody previously in the queue has been reset',
|
|
create: 'A queue for teams of {teamsize} has been created',
|
|
close: 'Queue has been closed',
|
|
join: 'Joined the queue',
|
|
leave: 'Left the queue'
|
|
},
|
|
|
|
api: {
|
|
player: {
|
|
embed: true,
|
|
title: '{name} ({id})',
|
|
url: 'https://uniteapi.dev/p/{nameEncoded}',
|
|
timestamp: true,
|
|
thumbnail: '{avatar}',
|
|
description: [
|
|
'Level {level}',
|
|
'{rank} {elo}',
|
|
'',
|
|
'**Battles** {battles}',
|
|
'**Wins** {wins}',
|
|
'**Win Rate** {winrate}'
|
|
]
|
|
}
|
|
},
|
|
|
|
error: {
|
|
|
|
main: {
|
|
missingToken: 'Missing Discord Token, please enter the bot token into the token file'
|
|
},
|
|
|
|
discord: {
|
|
noQueue: 'There is not an active queue in this channel, type `/open` to create one',
|
|
noChannel: 'Unable to find channel {channelId} for teams of {teamsize}',
|
|
noCreate: 'There is already an active queue in this channel for teams of {teamsize}',
|
|
inQueue: 'You are already in the queue',
|
|
notInQueue: 'You aren\'t in the queue',
|
|
notMod: 'Member is not a moderator'
|
|
},
|
|
|
|
general: {
|
|
noMember: 'Unable to retrieve guild member information, please try again',
|
|
noChannel: 'Unable to retrieve text channel information, please try again'
|
|
},
|
|
|
|
api: {
|
|
noUser: 'Unable to find user'
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
/* MAIN */
|
|
|
|
let LANGID = 'en';
|
|
if (!(LANGID in LANG))
|
|
throw 'language id does not exist';
|
|
|
|
export function setLang(langid: string) {
|
|
if (langid in LANG)
|
|
LANGID = langid;
|
|
else
|
|
throw 'language id does not exist';
|
|
}
|
|
|
|
/**
|
|
* reads language json (just strings)
|
|
* @param id ex: discord.error.noActiveQueue
|
|
* @returns language value, defaults to `id` parameter
|
|
*/
|
|
export function get(id: string, args: basicObject = {}): string {
|
|
|
|
const keySpl = id.split('.').map(k => k.trim()).filter(k => k);
|
|
|
|
let finding = LANG[LANGID];
|
|
|
|
for (const key of keySpl) {
|
|
|
|
if (key in finding) {
|
|
|
|
const found = finding[key];
|
|
|
|
if (typeof found === 'string')
|
|
return template(found, args);
|
|
|
|
if (found.embed === true)
|
|
return embedObjStr(found as embedObj, id);
|
|
|
|
finding = found as LangObj;
|
|
|
|
} else
|
|
break;
|
|
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* reads language json as an object (could be embed or just string)
|
|
* @param id ex: discord.error.noActiveQueue
|
|
* @returns language value, defaults to `id` parameter
|
|
*/
|
|
export function getEmbed(id: string, args: basicObject = {}): embedData {
|
|
|
|
const embedData: embedData = {
|
|
embeds: []
|
|
};
|
|
|
|
const keySpl = id.split('.').map(k => k.trim()).filter(k => k);
|
|
|
|
let finding = LANG[LANGID];
|
|
|
|
for (const key of keySpl) {
|
|
|
|
if (key in finding) {
|
|
|
|
const found = finding[key];
|
|
|
|
if (typeof found === 'string') {
|
|
embedData.content = template(found, args);
|
|
break;
|
|
}
|
|
|
|
if (found.embed === true) {
|
|
const embedObj = found as embedObj,
|
|
{content} = embedObj,
|
|
embed = embedObjEmbed(embedObj, args),
|
|
embedData: embedData = {
|
|
embeds: [embed]
|
|
};
|
|
|
|
if (content !== undefined)
|
|
embedData.content = content;
|
|
|
|
return embedData;
|
|
}
|
|
|
|
finding = found as LangObj;
|
|
|
|
} else
|
|
break;
|
|
|
|
}
|
|
|
|
return embedData;
|
|
}
|