Compare commits
2 Commits
513a9d1582
...
a3103f73c3
| Author | SHA1 | Date | |
|---|---|---|---|
| a3103f73c3 | |||
| 5348ab487b |
@@ -5,7 +5,7 @@
|
|||||||
"plugin:@typescript-eslint/recommended"
|
"plugin:@typescript-eslint/recommended"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": { "project": ["./tsconfig.json"] },
|
"parserOptions": { "project": ["./tsconfig.eslint.json"] },
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint"
|
"@typescript-eslint"
|
||||||
],
|
],
|
||||||
@@ -17,10 +17,7 @@
|
|||||||
"allowNumber" : false
|
"allowNumber" : false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
/* dev */
|
|
||||||
"no-debugger": "off",
|
|
||||||
|
|
||||||
/* important */
|
/* important */
|
||||||
"prefer-const": "error",
|
"prefer-const": "error",
|
||||||
"quotes": ["error", "single"],
|
"quotes": ["error", "single"],
|
||||||
|
|||||||
10
dist/api.js
vendored
10
dist/api.js
vendored
@@ -26,7 +26,7 @@ exports.getPlayerInteraction = exports.getPlayer = void 0;
|
|||||||
/*eslint prefer-const: "error"*/
|
/*eslint prefer-const: "error"*/
|
||||||
const cheerio = __importStar(require("cheerio"));
|
const cheerio = __importStar(require("cheerio"));
|
||||||
const https_1 = __importDefault(require("https"));
|
const https_1 = __importDefault(require("https"));
|
||||||
const util_1 = require("./util");
|
const main_1 = require("./util/main");
|
||||||
const Lang = __importStar(require("./lang"));
|
const Lang = __importStar(require("./lang"));
|
||||||
const uniteApiRegex = {
|
const uniteApiRegex = {
|
||||||
//$1 = name, $2 = id
|
//$1 = name, $2 = id
|
||||||
@@ -109,7 +109,7 @@ function readHTML(html) {
|
|||||||
extraLines.push(line);
|
extraLines.push(line);
|
||||||
}
|
}
|
||||||
if (lines.length === 0)
|
if (lines.length === 0)
|
||||||
throw (0, util_1.emsg)('Unable to read data, please try again');
|
throw (0, main_1.emsg)('Unable to read data, please try again');
|
||||||
//bring the first lines removed back into the data
|
//bring the first lines removed back into the data
|
||||||
lines = [
|
lines = [
|
||||||
...lines,
|
...lines,
|
||||||
@@ -122,7 +122,7 @@ function readHTML(html) {
|
|||||||
if (regex[0].test(line)) { //is master/has elo
|
if (regex[0].test(line)) { //is master/has elo
|
||||||
const regexData = line.match(regex[0]);
|
const regexData = line.match(regex[0]);
|
||||||
if (!regexData || regexData.length < 4)
|
if (!regexData || regexData.length < 4)
|
||||||
throw (0, util_1.emsg)('Unable to read data, please try again');
|
throw (0, main_1.emsg)('Unable to read data, please try again');
|
||||||
foundData.level = regexData[1];
|
foundData.level = regexData[1];
|
||||||
foundData.rank = regexData[2];
|
foundData.rank = regexData[2];
|
||||||
foundData.elo = regexData[3];
|
foundData.elo = regexData[3];
|
||||||
@@ -130,7 +130,7 @@ function readHTML(html) {
|
|||||||
else { //is not master/has a class
|
else { //is not master/has a class
|
||||||
const regexData = line.match(regex[1]);
|
const regexData = line.match(regex[1]);
|
||||||
if (!regexData || regexData.length < 4)
|
if (!regexData || regexData.length < 4)
|
||||||
throw (0, util_1.emsg)('Unable to read data, please try again');
|
throw (0, main_1.emsg)('Unable to read data, please try again');
|
||||||
foundData.level = regexData[1];
|
foundData.level = regexData[1];
|
||||||
foundData.rank = regexData[2];
|
foundData.rank = regexData[2];
|
||||||
foundData.class = regexData[3];
|
foundData.class = regexData[3];
|
||||||
@@ -210,7 +210,7 @@ async function getPlayerInteraction(interaction) {
|
|||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
const data = await getPlayer(username);
|
const data = await getPlayer(username);
|
||||||
if (data === null)
|
if (data === null)
|
||||||
throw (0, util_1.emsg)('api.noUser');
|
throw (0, main_1.emsg)('api.noUser');
|
||||||
else
|
else
|
||||||
sendPlayerEmbed(interaction, data);
|
sendPlayerEmbed(interaction, data);
|
||||||
}
|
}
|
||||||
|
|||||||
4
dist/index.js
vendored
4
dist/index.js
vendored
@@ -25,7 +25,7 @@ const api_1 = require("./api");
|
|||||||
const discord_1 = require("./discord");
|
const discord_1 = require("./discord");
|
||||||
const Lang = __importStar(require("./lang"));
|
const Lang = __importStar(require("./lang"));
|
||||||
const queue_1 = require("./queue");
|
const queue_1 = require("./queue");
|
||||||
const util_1 = require("./util");
|
const main_1 = require("./util/main");
|
||||||
const CLIENT = new discord_js_1.Client({ intents: [discord_js_1.Intents.FLAGS.GUILDS] });
|
const CLIENT = new discord_js_1.Client({ intents: [discord_js_1.Intents.FLAGS.GUILDS] });
|
||||||
//init logs with a timestamp
|
//init logs with a timestamp
|
||||||
console.log(new Date().toISOString() + '\n\n');
|
console.log(new Date().toISOString() + '\n\n');
|
||||||
@@ -76,7 +76,7 @@ CLIENT.on('interactionCreate', async (interaction) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e instanceof util_1.errorMessage) {
|
if (e instanceof main_1.errorMessage) {
|
||||||
if (interaction.deferred || interaction.replied)
|
if (interaction.deferred || interaction.replied)
|
||||||
interaction.editReply(e.msg);
|
interaction.editReply(e.msg);
|
||||||
else
|
else
|
||||||
|
|||||||
103
dist/lang.js
vendored
103
dist/lang.js
vendored
@@ -1,100 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getEmbed = exports.get = exports.setLang = void 0;
|
exports.getEmbed = exports.get = exports.setLang = void 0;
|
||||||
const discord_js_1 = require("discord.js");
|
const lang_1 = require("./util/lang");
|
||||||
/* UTIL FUNCS */
|
|
||||||
function template(str, args) {
|
|
||||||
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) {
|
|
||||||
if (typeof str === 'object')
|
|
||||||
return str.join('\n');
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
function resolveColor(color) {
|
|
||||||
color = color.replace(/[^0-9a-f]/gi, '');
|
|
||||||
const colorNum = [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, fallback = '') {
|
|
||||||
if (embedData.content !== undefined)
|
|
||||||
return bigString(embedData.content);
|
|
||||||
if (embedData.description !== undefined)
|
|
||||||
return bigString(embedData.description);
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
function embedObjEmbed(embedObj, args = {}) {
|
|
||||||
const embed = new discord_js_1.MessageEmbed(), { author, color, description, fields, footer, image, thumbnail, timestamp, title, url } = embedObj;
|
|
||||||
if (author !== undefined) {
|
|
||||||
let authorFix;
|
|
||||||
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;
|
|
||||||
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 = {
|
const LANG = {
|
||||||
en: {
|
en: {
|
||||||
main: {
|
main: {
|
||||||
@@ -190,9 +97,9 @@ function get(id, args = {}) {
|
|||||||
if (key in finding) {
|
if (key in finding) {
|
||||||
const found = finding[key];
|
const found = finding[key];
|
||||||
if (typeof found === 'string')
|
if (typeof found === 'string')
|
||||||
return template(found, args);
|
return (0, lang_1.template)(found, args);
|
||||||
if (found.embed === true)
|
if (found.embed === true)
|
||||||
return embedObjStr(found, id);
|
return (0, lang_1.embedObjStr)(found, id);
|
||||||
finding = found;
|
finding = found;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -219,11 +126,11 @@ function getEmbed(id, args = {}, otherOptions = {}) {
|
|||||||
if (key in finding) {
|
if (key in finding) {
|
||||||
const found = finding[key];
|
const found = finding[key];
|
||||||
if (typeof found === 'string') {
|
if (typeof found === 'string') {
|
||||||
embedData.content = template(found, args);
|
embedData.content = (0, lang_1.template)(found, args);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (found.embed === true) {
|
if (found.embed === true) {
|
||||||
const embedObj = found, { content } = embedObj, embed = embedObjEmbed(embedObj, args);
|
const embedObj = found, { content } = embedObj, embed = (0, lang_1.embedObjEmbed)(embedObj, args);
|
||||||
embedData.embeds.push(embed);
|
embedData.embeds.push(embed);
|
||||||
if (content !== undefined)
|
if (content !== undefined)
|
||||||
embedData.content = content;
|
embedData.content = content;
|
||||||
|
|||||||
21
dist/queue.js
vendored
21
dist/queue.js
vendored
@@ -26,9 +26,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
exports.QueueCommands = exports.queueContains = exports.discordInit = exports.queueRemove = exports.queueCreate = void 0;
|
exports.QueueCommands = exports.queueContains = exports.discordInit = exports.queueRemove = exports.queueCreate = void 0;
|
||||||
const discord_js_1 = require("discord.js");
|
const discord_js_1 = require("discord.js");
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const util_1 = require("./util");
|
|
||||||
const Lang = __importStar(require("./lang"));
|
const Lang = __importStar(require("./lang"));
|
||||||
//load queues from file
|
const discord_1 = require("./util/discord");
|
||||||
|
const main_1 = require("./util/main");
|
||||||
|
//load queues from file`
|
||||||
if (!fs.existsSync('./queues.json'))
|
if (!fs.existsSync('./queues.json'))
|
||||||
fs.writeFileSync('./queues.json', '{}');
|
fs.writeFileSync('./queues.json', '{}');
|
||||||
const _QUEUE = fs.readFileSync('./queues.json').toString(), QUEUE = new Map();
|
const _QUEUE = fs.readFileSync('./queues.json').toString(), QUEUE = new Map();
|
||||||
@@ -101,7 +102,7 @@ exports.discordInit = discordInit;
|
|||||||
function getInfo(interaction) {
|
function getInfo(interaction) {
|
||||||
const info = QUEUE.get(interaction.channelId);
|
const info = QUEUE.get(interaction.channelId);
|
||||||
if (!info)
|
if (!info)
|
||||||
throw (0, util_1.emsg)('discord.noQueue');
|
throw (0, main_1.emsg)('discord.noQueue');
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -111,8 +112,8 @@ function getInfo(interaction) {
|
|||||||
* @returns object containing each
|
* @returns object containing each
|
||||||
*/
|
*/
|
||||||
const getAll = (interaction) => ({
|
const getAll = (interaction) => ({
|
||||||
member: (0, util_1.getMember)(interaction),
|
member: (0, discord_1.getMember)(interaction),
|
||||||
channel: (0, util_1.getChannel)(interaction),
|
channel: (0, discord_1.getChannel)(interaction),
|
||||||
info: getInfo(interaction)
|
info: getInfo(interaction)
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
@@ -133,11 +134,11 @@ exports.queueContains = queueContains;
|
|||||||
* @throws errorMessage class if it cannot be left
|
* @throws errorMessage class if it cannot be left
|
||||||
*/
|
*/
|
||||||
function open(interaction) {
|
function open(interaction) {
|
||||||
(0, util_1.memberIsModThrow)(interaction);
|
(0, discord_1.memberIsModThrow)(interaction);
|
||||||
const { channelId } = interaction, teamsize = interaction.options.getInteger('teamsize', true);
|
const { channelId } = interaction, teamsize = interaction.options.getInteger('teamsize', true);
|
||||||
const existing = QUEUE.get(channelId);
|
const existing = QUEUE.get(channelId);
|
||||||
if (existing)
|
if (existing)
|
||||||
throw (0, util_1.emsg)(Lang.get('error.discord.noCreate', {
|
throw (0, main_1.emsg)(Lang.get('error.discord.noCreate', {
|
||||||
teamsize: existing.teamsize.toString()
|
teamsize: existing.teamsize.toString()
|
||||||
}));
|
}));
|
||||||
queueCreate(channelId, teamsize);
|
queueCreate(channelId, teamsize);
|
||||||
@@ -151,7 +152,7 @@ function open(interaction) {
|
|||||||
* @throws errorMessage class if it cannot be joined
|
* @throws errorMessage class if it cannot be joined
|
||||||
*/
|
*/
|
||||||
async function close(interaction) {
|
async function close(interaction) {
|
||||||
(0, util_1.memberIsModThrow)(interaction);
|
(0, discord_1.memberIsModThrow)(interaction);
|
||||||
QUEUE.delete(interaction.channelId);
|
QUEUE.delete(interaction.channelId);
|
||||||
await interaction.reply(Lang.get('discord.close'));
|
await interaction.reply(Lang.get('discord.close'));
|
||||||
}
|
}
|
||||||
@@ -177,7 +178,7 @@ async function queue(interaction) {
|
|||||||
async function join(interaction) {
|
async function join(interaction) {
|
||||||
const { member, info, channel } = getAll(interaction);
|
const { member, info, channel } = getAll(interaction);
|
||||||
if (queueContains(interaction))
|
if (queueContains(interaction))
|
||||||
throw (0, util_1.emsg)('discord.inQueue');
|
throw (0, main_1.emsg)('discord.inQueue');
|
||||||
info.players.push(member);
|
info.players.push(member);
|
||||||
QUEUE.set(interaction.channelId, info);
|
QUEUE.set(interaction.channelId, info);
|
||||||
await interaction.reply(Lang.get('discord.join'));
|
await interaction.reply(Lang.get('discord.join'));
|
||||||
@@ -191,7 +192,7 @@ async function join(interaction) {
|
|||||||
async function leave(interaction) {
|
async function leave(interaction) {
|
||||||
const { member, info } = getAll(interaction);
|
const { member, info } = getAll(interaction);
|
||||||
if (!queueContains(interaction))
|
if (!queueContains(interaction))
|
||||||
throw (0, util_1.emsg)('discord.notInQueue');
|
throw (0, main_1.emsg)('discord.notInQueue');
|
||||||
info.players.splice(info.players.indexOf(member), 1);
|
info.players.splice(info.players.indexOf(member), 1);
|
||||||
QUEUE.set(interaction.channelId, info);
|
QUEUE.set(interaction.channelId, info);
|
||||||
await interaction.reply(Lang.get('discord.leave'));
|
await interaction.reply(Lang.get('discord.leave'));
|
||||||
|
|||||||
41
dist/util/discord.js
vendored
Normal file
41
dist/util/discord.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.memberIsModThrow = exports.memberIsMod = exports.getChannel = exports.getMember = void 0;
|
||||||
|
const discord_js_1 = require("discord.js");
|
||||||
|
const main_1 = require("./main");
|
||||||
|
/**
|
||||||
|
* get the GuildMember of an interaction
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be read
|
||||||
|
* @returns member
|
||||||
|
*/
|
||||||
|
function getMember(interaction) {
|
||||||
|
const member = interaction.member;
|
||||||
|
if (!(member instanceof discord_js_1.GuildMember))
|
||||||
|
throw (0, main_1.emsg)('general.noMember');
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
exports.getMember = getMember;
|
||||||
|
/**
|
||||||
|
* get the TextChannel of an interaction
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be read
|
||||||
|
* @returns member
|
||||||
|
*/
|
||||||
|
function getChannel(interaction) {
|
||||||
|
const channel = interaction.channel;
|
||||||
|
if (!(channel instanceof discord_js_1.TextChannel))
|
||||||
|
throw (0, main_1.emsg)('general.noChannel');
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
exports.getChannel = getChannel;
|
||||||
|
function memberIsMod(interaction) {
|
||||||
|
const member = getMember(interaction);
|
||||||
|
return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES');
|
||||||
|
}
|
||||||
|
exports.memberIsMod = memberIsMod;
|
||||||
|
function memberIsModThrow(interaction) {
|
||||||
|
if (!memberIsMod(interaction))
|
||||||
|
throw (0, main_1.emsg)('discord.notMod');
|
||||||
|
}
|
||||||
|
exports.memberIsModThrow = memberIsModThrow;
|
||||||
100
dist/util/lang.js
vendored
Normal file
100
dist/util/lang.js
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.embedObjEmbed = exports.embedObjStr = exports.resolveColor = exports.bigString = exports.template = void 0;
|
||||||
|
const discord_js_1 = require("discord.js");
|
||||||
|
function template(str, args) {
|
||||||
|
return str.replace(/{\w+}/g, str => {
|
||||||
|
const key = str.substring(1, str.length - 1);
|
||||||
|
if (key in args)
|
||||||
|
return args[key];
|
||||||
|
return key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.template = template;
|
||||||
|
function bigString(str) {
|
||||||
|
if (typeof str === 'object')
|
||||||
|
return str.join('\n');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
exports.bigString = bigString;
|
||||||
|
function resolveColor(color) {
|
||||||
|
color = color.replace(/[^0-9a-f]/gi, '');
|
||||||
|
const colorNum = [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;
|
||||||
|
}
|
||||||
|
exports.resolveColor = resolveColor;
|
||||||
|
function embedObjStr(embedData, fallback = '') {
|
||||||
|
if (embedData.content !== undefined)
|
||||||
|
return bigString(embedData.content);
|
||||||
|
if (embedData.description !== undefined)
|
||||||
|
return bigString(embedData.description);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
exports.embedObjStr = embedObjStr;
|
||||||
|
function embedObjEmbed(embedObj, args = {}) {
|
||||||
|
const embed = new discord_js_1.MessageEmbed(), { author, color, description, fields, footer, image, thumbnail, timestamp, title, url } = embedObj;
|
||||||
|
if (author !== undefined) {
|
||||||
|
let authorFix;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
exports.embedObjEmbed = embedObjEmbed;
|
||||||
60
dist/util/main.js
vendored
Normal file
60
dist/util/main.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.emsg = exports.errorMessage = exports.shuffle = void 0;
|
||||||
|
const Lang = __importStar(require("../lang"));
|
||||||
|
/**
|
||||||
|
* shuffles an array
|
||||||
|
* https://stackoverflow.com/a/2450976/2856416
|
||||||
|
* @param array an array
|
||||||
|
* @returns an array but shuffled
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
function shuffle(array) {
|
||||||
|
let currentIndex = array.length, randomIndex;
|
||||||
|
// While there remain elements to shuffle...
|
||||||
|
while (currentIndex != 0) {
|
||||||
|
// Pick a remaining element...
|
||||||
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
|
currentIndex--;
|
||||||
|
// And swap it with the current element.
|
||||||
|
[array[currentIndex], array[randomIndex]] = [
|
||||||
|
array[randomIndex], array[currentIndex]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
exports.shuffle = shuffle;
|
||||||
|
class errorMessage {
|
||||||
|
constructor(msg, ephemeral = true) {
|
||||||
|
this.msg = msg;
|
||||||
|
this.ephemeral = ephemeral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.errorMessage = errorMessage;
|
||||||
|
/**
|
||||||
|
* a simple class to contain an error message and related data
|
||||||
|
* @param msg error message
|
||||||
|
* @param ephemeral (default=true)
|
||||||
|
* @returns new errorMessage
|
||||||
|
*/
|
||||||
|
const emsg = (msg, ephemeral = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral);
|
||||||
|
exports.emsg = emsg;
|
||||||
17
src/api.ts
17
src/api.ts
@@ -3,8 +3,9 @@ import * as cheerio from 'cheerio';
|
|||||||
import { CommandInteraction } from 'discord.js';
|
import { CommandInteraction } from 'discord.js';
|
||||||
import { IncomingMessage } from 'http';
|
import { IncomingMessage } from 'http';
|
||||||
import http from 'https';
|
import http from 'https';
|
||||||
import { emsg } from './util';
|
import { emsg } from './util/main';
|
||||||
import * as Lang from './lang';
|
import * as Lang from './lang';
|
||||||
|
import { uniteApiData } from './types/api';
|
||||||
|
|
||||||
const uniteApiRegex = {
|
const uniteApiRegex = {
|
||||||
//$1 = name, $2 = id
|
//$1 = name, $2 = id
|
||||||
@@ -16,20 +17,6 @@ const uniteApiRegex = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
type uniteApiData = {
|
|
||||||
name: string,
|
|
||||||
id: string,
|
|
||||||
avatar: string,
|
|
||||||
|
|
||||||
level: string,
|
|
||||||
rank: string,
|
|
||||||
class: string|null,
|
|
||||||
elo: string|null,
|
|
||||||
battles: string,
|
|
||||||
wins: string,
|
|
||||||
winrate: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the html of the uniteApi page for the player
|
* gets the html of the uniteApi page for the player
|
||||||
* @param name name of player
|
* @param name name of player
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { getPlayerInteraction } from './api';
|
|||||||
import { registerCommands } from './discord';
|
import { registerCommands } from './discord';
|
||||||
import * as Lang from './lang';
|
import * as Lang from './lang';
|
||||||
import { discordInit, QueueCommands } from './queue';
|
import { discordInit, QueueCommands } from './queue';
|
||||||
import { errorMessage } from './util';
|
import { errorMessage } from './util/main';
|
||||||
const CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
const CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
||||||
|
|
||||||
//init logs with a timestamp
|
//init logs with a timestamp
|
||||||
|
|||||||
199
src/lang.ts
199
src/lang.ts
@@ -1,199 +1,4 @@
|
|||||||
import { MessageEmbed } from 'discord.js';
|
import { embedObjEmbed, embedObjStr, template } from './util/lang';
|
||||||
|
|
||||||
/* TYPES */
|
|
||||||
|
|
||||||
//this is a generic type, and needs 'any'
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type basicObject = {[keys: string]: any};
|
|
||||||
type basicObjectStr = {[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: basicObjectStr = {}): 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 = {
|
const LANG: LangObjWhole = {
|
||||||
|
|
||||||
@@ -378,5 +183,3 @@ export function getEmbed(id: string, args: basicObjectStr = {}, otherOptions: ba
|
|||||||
|
|
||||||
return embedData;
|
return embedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger;
|
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ join message should contain your current position in the queue, editing it to ke
|
|||||||
|
|
||||||
import { Client, CommandInteraction, TextChannel } from 'discord.js';
|
import { Client, CommandInteraction, TextChannel } from 'discord.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { emsg, getChannel, getMember, memberIsModThrow, queueInfo, queueInfoBase } from './util';
|
|
||||||
import * as Lang from './lang';
|
import * as Lang from './lang';
|
||||||
|
import { queueInfo, queueInfoBase } from './types/queue';
|
||||||
|
import { getChannel, getMember, memberIsModThrow } from './util/discord';
|
||||||
|
import { emsg } from './util/main';
|
||||||
|
|
||||||
//load queues from file
|
//load queues from file`
|
||||||
if (!fs.existsSync('./queues.json'))
|
if (!fs.existsSync('./queues.json'))
|
||||||
fs.writeFileSync('./queues.json', '{}');
|
fs.writeFileSync('./queues.json', '{}');
|
||||||
|
|
||||||
|
|||||||
13
src/types/api.d.ts
vendored
Normal file
13
src/types/api.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export interface uniteApiData {
|
||||||
|
name: string,
|
||||||
|
id: string,
|
||||||
|
avatar: string,
|
||||||
|
|
||||||
|
level: string,
|
||||||
|
rank: string,
|
||||||
|
class: string|null,
|
||||||
|
elo: string|null,
|
||||||
|
battles: string,
|
||||||
|
wins: string,
|
||||||
|
winrate: string
|
||||||
|
}
|
||||||
55
src/types/lang.d.ts
vendored
Normal file
55
src/types/lang.d.ts
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
//this is a generic type, and needs 'any'
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
type basicObject = {[keys: string]: any};
|
||||||
|
type basicObjectStr = {[keys: string]: 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?: string,
|
||||||
|
/**
|
||||||
|
* #FFFFFF
|
||||||
|
*/
|
||||||
|
color?: string,
|
||||||
|
footer?: string | footerData,
|
||||||
|
thumbnail?: string,
|
||||||
|
/**
|
||||||
|
* URL
|
||||||
|
*/
|
||||||
|
image?: string,
|
||||||
|
/**
|
||||||
|
* URL
|
||||||
|
*/
|
||||||
|
author?: string | authorData,
|
||||||
|
fields?: embedField[],
|
||||||
|
timestamp?: boolean | string | number
|
||||||
|
}
|
||||||
|
|
||||||
|
type LangObj = { [keys:string]: LangObj | embedObj | string }
|
||||||
|
type LangObjWhole = { [langid:string]: LangObj }
|
||||||
8
src/types/queue.d.ts
vendored
Normal file
8
src/types/queue.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { GuildMember } from 'discord.js';
|
||||||
|
|
||||||
|
export interface queueInfoBase {
|
||||||
|
teamsize: number
|
||||||
|
}
|
||||||
|
export interface queueInfo extends queueInfoBase {
|
||||||
|
players: GuildMember[]
|
||||||
|
}
|
||||||
97
src/util.ts
97
src/util.ts
@@ -1,97 +0,0 @@
|
|||||||
import { CommandInteraction, GuildMember, TextChannel } from 'discord.js';
|
|
||||||
import * as Lang from './lang';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* shuffles an array
|
|
||||||
* https://stackoverflow.com/a/2450976/2856416
|
|
||||||
* @param array an array
|
|
||||||
* @returns an array but shuffled
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export function shuffle(array: any[]) {
|
|
||||||
let currentIndex = array.length, randomIndex;
|
|
||||||
|
|
||||||
// While there remain elements to shuffle...
|
|
||||||
while (currentIndex != 0) {
|
|
||||||
|
|
||||||
// Pick a remaining element...
|
|
||||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
||||||
currentIndex--;
|
|
||||||
|
|
||||||
// And swap it with the current element.
|
|
||||||
[array[currentIndex], array[randomIndex]] = [
|
|
||||||
array[randomIndex], array[currentIndex]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class errorMessage {
|
|
||||||
public msg: string;
|
|
||||||
public ephemeral: boolean;
|
|
||||||
|
|
||||||
constructor(msg: string, ephemeral = true) {
|
|
||||||
this.msg = msg;
|
|
||||||
this.ephemeral = ephemeral;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a simple class to contain an error message and related data
|
|
||||||
* @param msg error message
|
|
||||||
* @param ephemeral (default=true)
|
|
||||||
* @returns new errorMessage
|
|
||||||
*/
|
|
||||||
export const emsg = (msg: string, ephemeral = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface queueInfoBase {
|
|
||||||
teamsize: number
|
|
||||||
}
|
|
||||||
export interface queueInfo extends queueInfoBase{
|
|
||||||
players: GuildMember[]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the GuildMember of an interaction
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be read
|
|
||||||
* @returns member
|
|
||||||
*/
|
|
||||||
export function getMember(interaction: CommandInteraction): GuildMember {
|
|
||||||
const member = interaction.member;
|
|
||||||
|
|
||||||
if (!(member instanceof GuildMember))
|
|
||||||
throw emsg('general.noMember');
|
|
||||||
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the TextChannel of an interaction
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be read
|
|
||||||
* @returns member
|
|
||||||
*/
|
|
||||||
export function getChannel(interaction: CommandInteraction): TextChannel {
|
|
||||||
const channel = interaction.channel;
|
|
||||||
|
|
||||||
if (!(channel instanceof TextChannel))
|
|
||||||
throw emsg('general.noChannel');
|
|
||||||
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function memberIsMod(interaction: CommandInteraction): boolean {
|
|
||||||
const member = getMember(interaction);
|
|
||||||
return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function memberIsModThrow(interaction: CommandInteraction) {
|
|
||||||
if (!memberIsMod(interaction))
|
|
||||||
throw emsg('discord.notMod');
|
|
||||||
}
|
|
||||||
43
src/util/discord.ts
Normal file
43
src/util/discord.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { CommandInteraction, GuildMember, TextChannel } from 'discord.js';
|
||||||
|
import { emsg } from './main';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the GuildMember of an interaction
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be read
|
||||||
|
* @returns member
|
||||||
|
*/
|
||||||
|
export function getMember(interaction: CommandInteraction): GuildMember {
|
||||||
|
const member = interaction.member;
|
||||||
|
|
||||||
|
if (!(member instanceof GuildMember))
|
||||||
|
throw emsg('general.noMember');
|
||||||
|
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the TextChannel of an interaction
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be read
|
||||||
|
* @returns member
|
||||||
|
*/
|
||||||
|
export function getChannel(interaction: CommandInteraction): TextChannel {
|
||||||
|
const channel = interaction.channel;
|
||||||
|
|
||||||
|
if (!(channel instanceof TextChannel))
|
||||||
|
throw emsg('general.noChannel');
|
||||||
|
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function memberIsMod(interaction: CommandInteraction): boolean {
|
||||||
|
const member = getMember(interaction);
|
||||||
|
return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function memberIsModThrow(interaction: CommandInteraction) {
|
||||||
|
if (!memberIsMod(interaction))
|
||||||
|
throw emsg('discord.notMod');
|
||||||
|
}
|
||||||
142
src/util/lang.ts
Normal file
142
src/util/lang.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import { MessageEmbed } from 'discord.js';
|
||||||
|
|
||||||
|
export 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;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bigString(str: bigString): string {
|
||||||
|
if (typeof str === 'object')
|
||||||
|
return str.join('\n');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
export 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function embedObjStr(embedData: embedObj, fallback = ''): string {
|
||||||
|
|
||||||
|
if (embedData.content !== undefined)
|
||||||
|
return bigString(embedData.content);
|
||||||
|
|
||||||
|
if (embedData.description !== undefined)
|
||||||
|
return bigString(embedData.description);
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function embedObjEmbed(embedObj: embedObj, args: basicObjectStr = {}): 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;
|
||||||
|
}
|
||||||
47
src/util/main.ts
Normal file
47
src/util/main.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import * as Lang from '../lang';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shuffles an array
|
||||||
|
* https://stackoverflow.com/a/2450976/2856416
|
||||||
|
* @param array an array
|
||||||
|
* @returns an array but shuffled
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export function shuffle(array: any[]) {
|
||||||
|
let currentIndex = array.length, randomIndex;
|
||||||
|
|
||||||
|
// While there remain elements to shuffle...
|
||||||
|
while (currentIndex != 0) {
|
||||||
|
|
||||||
|
// Pick a remaining element...
|
||||||
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
|
currentIndex--;
|
||||||
|
|
||||||
|
// And swap it with the current element.
|
||||||
|
[array[currentIndex], array[randomIndex]] = [
|
||||||
|
array[randomIndex], array[currentIndex]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class errorMessage {
|
||||||
|
public msg: string;
|
||||||
|
public ephemeral: boolean;
|
||||||
|
|
||||||
|
constructor(msg: string, ephemeral = true) {
|
||||||
|
this.msg = msg;
|
||||||
|
this.ephemeral = ephemeral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a simple class to contain an error message and related data
|
||||||
|
* @param msg error message
|
||||||
|
* @param ephemeral (default=true)
|
||||||
|
* @returns new errorMessage
|
||||||
|
*/
|
||||||
|
export const emsg = (msg: string, ephemeral = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral);
|
||||||
|
|
||||||
11
tsconfig.eslint.json
Normal file
11
tsconfig.eslint.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Special typescript project file, used by eslint only.
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": [
|
||||||
|
// repeated from base config's "include" setting
|
||||||
|
"src",
|
||||||
|
|
||||||
|
// these are the eslint-only inclusions
|
||||||
|
".eslintrc.json",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -11,5 +11,11 @@
|
|||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
}
|
"typeRoots": [
|
||||||
|
"./src/types/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user