Compare commits
2 Commits
84482be886
...
f5ab2b4297
| Author | SHA1 | Date | |
|---|---|---|---|
| f5ab2b4297 | |||
| 983f742f0d |
55
.eslintrc.json
Normal file
55
.eslintrc.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": { "project": ["./tsconfig.json"] },
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/strict-boolean-expressions": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
"allowString" : false,
|
||||||
|
"allowNumber" : false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
/* important */
|
||||||
|
"prefer-const": "error",
|
||||||
|
"quotes": ["error", "single"],
|
||||||
|
|
||||||
|
"block-scoped-var": "error",
|
||||||
|
"camelcase": "error",
|
||||||
|
"consistent-this": ["error", "that"],
|
||||||
|
"no-else-return": "error",
|
||||||
|
"no-eq-null": "error",
|
||||||
|
"no-floating-decimal": "error",
|
||||||
|
"no-implicit-coercion": "error",
|
||||||
|
"no-implied-eval": "error",
|
||||||
|
"no-invalid-this": "error",
|
||||||
|
"require-await": "error",
|
||||||
|
"yoda": "error",
|
||||||
|
|
||||||
|
"semi": ["error", "always"],
|
||||||
|
"semi-style": ["error", "last"],
|
||||||
|
|
||||||
|
/* less important */
|
||||||
|
"no-unreachable-loop": "error",
|
||||||
|
"no-unused-private-class-members": "error",
|
||||||
|
"no-use-before-define": "error",
|
||||||
|
"no-unmodified-loop-condition": "error",
|
||||||
|
"no-duplicate-imports": "error",
|
||||||
|
"no-promise-executor-return": "error",
|
||||||
|
"no-self-compare": "error",
|
||||||
|
"no-constructor-return": "error",
|
||||||
|
"no-template-curly-in-string": "error",
|
||||||
|
"array-callback-return": "error",
|
||||||
|
"no-eval": "error",
|
||||||
|
"no-extend-native": "error",
|
||||||
|
"no-extra-bind": "error"
|
||||||
|
},
|
||||||
|
"ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
|
||||||
|
}
|
||||||
2393
package-lock.json
generated
2393
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^17.0.17",
|
"@types/node": "^17.0.17",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
||||||
"discord-api-types": "^0.26.1",
|
"discord-api-types": "^0.26.1",
|
||||||
"npm-watch": "^0.11.0",
|
"npm-watch": "^0.11.0",
|
||||||
"ts-node": "^10.4.0",
|
"ts-node": "^10.4.0",
|
||||||
|
|||||||
80
src/api.ts
80
src/api.ts
@@ -1,3 +1,4 @@
|
|||||||
|
/*eslint prefer-const: "error"*/
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import { CommandInteraction, MessageEmbed } from 'discord.js';
|
import { CommandInteraction, MessageEmbed } from 'discord.js';
|
||||||
import { IncomingMessage } from 'http';
|
import { IncomingMessage } from 'http';
|
||||||
@@ -12,7 +13,7 @@ const uniteApiRegex = {
|
|||||||
/lv\.(\d+) (\w+) \((\d+)\)/i, //master
|
/lv\.(\d+) (\w+) \((\d+)\)/i, //master
|
||||||
/lv\.(\d+) (\w+): class (\d+)/i //other
|
/lv\.(\d+) (\w+): class (\d+)/i //other
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|
||||||
type uniteApiData = {
|
type uniteApiData = {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -76,30 +77,30 @@ function getHTML(name: string): Promise<string> {
|
|||||||
* @throws errorMessage class if the request fails
|
* @throws errorMessage class if the request fails
|
||||||
*/
|
*/
|
||||||
function readHTML(html: string): uniteApiData {
|
function readHTML(html: string): uniteApiData {
|
||||||
let $ = cheerio.load(html)
|
const $ = cheerio.load(html),
|
||||||
let metaElems = $('meta').toArray(),
|
|
||||||
foundData: uniteApiData = {
|
foundData: uniteApiData = {
|
||||||
name: "",
|
name: '',
|
||||||
id: "",
|
id: '',
|
||||||
avatar: "",
|
avatar: '',
|
||||||
|
|
||||||
level: "",
|
level: '',
|
||||||
rank: "",
|
rank: '',
|
||||||
elo: null,
|
elo: null,
|
||||||
class: null,
|
class: null,
|
||||||
battles: "",
|
battles: '',
|
||||||
wins: "",
|
wins: '',
|
||||||
winrate: ""
|
winrate: ''
|
||||||
};
|
};
|
||||||
|
let metaElems = $('meta').toArray();
|
||||||
|
|
||||||
//filter down to just ones named "og:..."
|
//filter down to just ones named "og:..."
|
||||||
metaElems = metaElems.filter((el: cheerio.Element) => el.attribs.property?.startsWith('og:'));
|
metaElems = metaElems.filter(el => el.attribs.property?.startsWith('og:'));
|
||||||
|
|
||||||
metaElems.forEach((el: cheerio.Element) => {
|
metaElems.forEach(el => {
|
||||||
let attr = el.attribs;
|
const attr = el.attribs;
|
||||||
|
|
||||||
if (attr.property === 'og:title') {
|
if (attr.property === 'og:title') {
|
||||||
let data = uniteApiRegex.ogtitle.exec(attr.content);
|
const data = uniteApiRegex.ogtitle.exec(attr.content);
|
||||||
if (data !== null && data.length >= 3) {
|
if (data !== null && data.length >= 3) {
|
||||||
foundData.name = data[1];
|
foundData.name = data[1];
|
||||||
foundData.id = data[2];
|
foundData.id = data[2];
|
||||||
@@ -107,17 +108,17 @@ function readHTML(html: string): uniteApiData {
|
|||||||
} else if (attr.property === 'og:description') {
|
} else if (attr.property === 'og:description') {
|
||||||
|
|
||||||
//all lines
|
//all lines
|
||||||
let lines = attr.content.split('\n').map((l: string) => l.trim()),
|
let lines = attr.content.split('\n').map(l => l.trim());
|
||||||
extraLines: string[] = [];
|
const extraLines: string[] = [];
|
||||||
|
|
||||||
//ensure first line is correct
|
//ensure first line is correct
|
||||||
while (lines.length && !/pok.mon unite/i.test(lines[0])) {
|
while ((lines.length > 0) && !/pok.mon unite/i.test(lines[0])) {
|
||||||
let line = lines.shift();
|
const line = lines.shift();
|
||||||
if (line)
|
if (line !== undefined)
|
||||||
extraLines.push(line);
|
extraLines.push(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lines.length)
|
if (lines.length === 0)
|
||||||
throw emsg('Unable to read data, please try again');
|
throw 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
|
||||||
@@ -129,13 +130,12 @@ function readHTML(html: string): uniteApiData {
|
|||||||
//first line
|
//first line
|
||||||
{
|
{
|
||||||
//will be only text after "pokemon unite:"
|
//will be only text after "pokemon unite:"
|
||||||
let line = lines[0].split(':').slice(1).join(':').trim();
|
const line = lines[0].split(':').slice(1).join(':').trim(),
|
||||||
|
regex = uniteApiRegex.ogdescription;
|
||||||
let regex = uniteApiRegex.ogdescription;
|
|
||||||
|
|
||||||
if (regex[0].test(line)) { //is master/has elo
|
if (regex[0].test(line)) { //is master/has elo
|
||||||
|
|
||||||
let regexData = line.match(regex[0]);
|
const regexData = line.match(regex[0]);
|
||||||
|
|
||||||
if (!regexData || regexData.length < 4)
|
if (!regexData || regexData.length < 4)
|
||||||
throw emsg('Unable to read data, please try again');
|
throw emsg('Unable to read data, please try again');
|
||||||
@@ -146,7 +146,7 @@ function readHTML(html: string): uniteApiData {
|
|||||||
|
|
||||||
} else { //is not master/has a class
|
} else { //is not master/has a class
|
||||||
|
|
||||||
let regexData = line.match(regex[1]);
|
const regexData = line.match(regex[1]);
|
||||||
|
|
||||||
if (!regexData || regexData.length < 4)
|
if (!regexData || regexData.length < 4)
|
||||||
throw emsg('Unable to read data, please try again');
|
throw emsg('Unable to read data, please try again');
|
||||||
@@ -162,9 +162,9 @@ function readHTML(html: string): uniteApiData {
|
|||||||
lines.shift();
|
lines.shift();
|
||||||
|
|
||||||
//rest of lines
|
//rest of lines
|
||||||
lines.forEach((line: string) => {
|
lines.forEach(line => {
|
||||||
|
|
||||||
let split = line.split(':').map((l: string) => l.trim()),
|
const split = line.split(':').map(l => l.trim()),
|
||||||
key = split[0].toLowerCase().replace(/[^\w]/g, ''),
|
key = split[0].toLowerCase().replace(/[^\w]/g, ''),
|
||||||
value = split[1];
|
value = split[1];
|
||||||
|
|
||||||
@@ -186,7 +186,9 @@ function readHTML(html: string): uniteApiData {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
foundData.avatar = $('.player-card-image img').attr('src') || "";
|
const imgSrc = $('.player-card-image img').attr('src');
|
||||||
|
|
||||||
|
foundData.avatar = imgSrc !== undefined ? imgSrc : '';
|
||||||
foundData.avatar = foundData.avatar.replace('../', 'https://uniteapi.dev/');
|
foundData.avatar = foundData.avatar.replace('../', 'https://uniteapi.dev/');
|
||||||
|
|
||||||
return foundData;
|
return foundData;
|
||||||
@@ -199,7 +201,7 @@ function readHTML(html: string): uniteApiData {
|
|||||||
* @returns boolean, valid or invalid
|
* @returns boolean, valid or invalid
|
||||||
*/
|
*/
|
||||||
function verifyData(data: uniteApiData): boolean {
|
function verifyData(data: uniteApiData): boolean {
|
||||||
if (data.id.length)
|
if (data.id.length > 0)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -210,8 +212,8 @@ function verifyData(data: uniteApiData): boolean {
|
|||||||
* @returns player data
|
* @returns player data
|
||||||
*/
|
*/
|
||||||
export async function getPlayer(name: string): Promise<uniteApiData|null> {
|
export async function getPlayer(name: string): Promise<uniteApiData|null> {
|
||||||
let html = await getHTML(name);
|
const html = await getHTML(name),
|
||||||
let data = readHTML(html);
|
data = readHTML(html);
|
||||||
if (verifyData(data))
|
if (verifyData(data))
|
||||||
return data;
|
return data;
|
||||||
return null;
|
return null;
|
||||||
@@ -219,13 +221,19 @@ export async function getPlayer(name: string): Promise<uniteApiData|null> {
|
|||||||
|
|
||||||
async function sendPlayerEmbed(interaction: CommandInteraction, data: uniteApiData) {
|
async function sendPlayerEmbed(interaction: CommandInteraction, data: uniteApiData) {
|
||||||
|
|
||||||
let embed = new MessageEmbed()
|
let eloStr: string;
|
||||||
|
if (data.elo !== null)
|
||||||
|
eloStr = `(${data.elo})`;
|
||||||
|
else
|
||||||
|
eloStr = `Class ${data.class}`;
|
||||||
|
|
||||||
|
const embed = new MessageEmbed()
|
||||||
.setTitle(`${data.name} (${data.id})`)
|
.setTitle(`${data.name} (${data.id})`)
|
||||||
.setURL(`https://uniteapi.dev/p/${encodeURIComponent(data.name)}`)
|
.setURL(`https://uniteapi.dev/p/${encodeURIComponent(data.name)}`)
|
||||||
.setTimestamp()
|
.setTimestamp()
|
||||||
.setThumbnail(data.avatar)
|
.setThumbnail(data.avatar)
|
||||||
.setDescription(`Level ${data.level}
|
.setDescription(`Level ${data.level}
|
||||||
${data.rank} ${data.elo ? `(${data.elo})` : `Class ${data.class}`}
|
${data.rank} ${eloStr}
|
||||||
|
|
||||||
**Battles** ${data.battles}
|
**Battles** ${data.battles}
|
||||||
**Wins** ${data.wins}
|
**Wins** ${data.wins}
|
||||||
@@ -240,10 +248,10 @@ ${data.rank} ${data.elo ? `(${data.elo})` : `Class ${data.class}`}
|
|||||||
* @throws errorMessage class if the user cannot be found
|
* @throws errorMessage class if the user cannot be found
|
||||||
*/
|
*/
|
||||||
export async function getPlayerInteraction(interaction: CommandInteraction) {
|
export async function getPlayerInteraction(interaction: CommandInteraction) {
|
||||||
let username = interaction.options.getString('username', true);
|
const username = interaction.options.getString('username', true);
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
|
|
||||||
let data = await getPlayer(username);
|
const data = await getPlayer(username);
|
||||||
if (data === null)
|
if (data === null)
|
||||||
throw emsg('api.noUser');
|
throw emsg('api.noUser');
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable camelcase */
|
||||||
import { REST } from '@discordjs/rest';
|
import { REST } from '@discordjs/rest';
|
||||||
import { Routes } from 'discord-api-types/v9';
|
import { Routes } from 'discord-api-types/v9';
|
||||||
|
|
||||||
@@ -45,8 +46,8 @@ const commands = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]/*,
|
];
|
||||||
commandNames = commands.map(c => c.name);*/
|
/*commandNames = commands.map(c => c.name);*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* register/reload commands on guild(s)
|
* register/reload commands on guild(s)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Client, Intents } from 'discord.js';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { getPlayerInteraction } from './api';
|
import { getPlayerInteraction } from './api';
|
||||||
import { registerCommands } from './discord';
|
import { registerCommands } from './discord';
|
||||||
import { 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';
|
||||||
const CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
const CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
||||||
|
|||||||
99
src/lang.ts
99
src/lang.ts
@@ -26,7 +26,7 @@ const LANG: LangObjWhole = {
|
|||||||
discord: {
|
discord: {
|
||||||
noQueue: 'There is not an active queue in this channel, type `/open` to create one',
|
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}',
|
noChannel: 'Unable to find channel {channelId} for teams of {teamsize}',
|
||||||
noCreate: 'There is already an active queue in this channel 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',
|
inQueue: 'You are already in the queue',
|
||||||
notInQueue: 'You aren\'t in the queue',
|
notInQueue: 'You aren\'t in the queue',
|
||||||
notMod: 'Member is not a moderator'
|
notMod: 'Member is not a moderator'
|
||||||
@@ -45,64 +45,61 @@ const LANG: LangObjWhole = {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
export namespace Lang {
|
|
||||||
|
|
||||||
var LANGID = 'en';
|
let LANGID = 'en';
|
||||||
if (!(LANGID in LANG))
|
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';
|
throw 'language id does not exist';
|
||||||
|
}
|
||||||
|
|
||||||
export function setLang(langid: string) {
|
function template(str: string, args: {[keys: string]: string}): string {
|
||||||
if (langid in LANG)
|
|
||||||
LANGID = langid;
|
|
||||||
else
|
|
||||||
throw 'language id does not exist';
|
|
||||||
}
|
|
||||||
|
|
||||||
function template(str: string, args: {[keys: string]: string}): string {
|
return str.replace(/{\w+}/g, str => {
|
||||||
|
|
||||||
return str.replace(/{\w+}/g, str => {
|
const key = str.substring(1, str.length-1);
|
||||||
|
|
||||||
let key = str.substring(1, str.length-1);
|
if (key in args)
|
||||||
|
return args[key];
|
||||||
|
|
||||||
if (key in args)
|
return key;
|
||||||
return args[key];
|
|
||||||
|
|
||||||
return key;
|
});
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads language json
|
|
||||||
* @param id ex: discord.error.noActiveQueue
|
|
||||||
* @returns language value, defaults to `id` parameter
|
|
||||||
*/
|
|
||||||
export function get(id: string, args: {[keys: string]: string} = {}): string {//discord.error.noActiveQueue
|
|
||||||
|
|
||||||
let keySpl = id.split('.').map(k => k.trim()).filter(k => k);
|
|
||||||
|
|
||||||
let finding = LANG[LANGID];
|
|
||||||
|
|
||||||
for (let key of keySpl) {
|
|
||||||
|
|
||||||
if (key in finding) {
|
|
||||||
|
|
||||||
let found = finding[key];
|
|
||||||
|
|
||||||
if (typeof found === 'string')
|
|
||||||
return template(found, args);
|
|
||||||
|
|
||||||
finding = found;
|
|
||||||
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads language json
|
||||||
|
* @param id ex: discord.error.noActiveQueue
|
||||||
|
* @returns language value, defaults to `id` parameter
|
||||||
|
*/
|
||||||
|
export function get(id: string, args: {[keys: string]: string} = {}): string {//discord.error.noActiveQueue
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
finding = found;
|
||||||
|
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
349
src/queue.ts
349
src/queue.ts
@@ -3,10 +3,10 @@
|
|||||||
join message should contain your current position in the queue, editing it to keep it current
|
join message should contain your current position in the queue, editing it to keep it current
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Client, CommandInteraction, MessageEmbed, TextChannel } from "discord.js";
|
import { Client, CommandInteraction, MessageEmbed, TextChannel } from 'discord.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { emsg, getChannel, getMember, memberIsModThrow, queueInfo, queueInfoBase } from "./util";
|
import { emsg, getChannel, getMember, memberIsModThrow, queueInfo, queueInfoBase } from './util';
|
||||||
import { Lang } from './lang';
|
import * as Lang from './lang';
|
||||||
|
|
||||||
//load queues from file
|
//load queues from file
|
||||||
if (!fs.existsSync('./queues.json'))
|
if (!fs.existsSync('./queues.json'))
|
||||||
@@ -17,22 +17,24 @@ const _QUEUE = fs.readFileSync('./queues.json').toString(),
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
let queueJson = JSON.parse(_QUEUE);
|
const queueJson = JSON.parse(_QUEUE);
|
||||||
|
|
||||||
for (let channelId in queueJson) {
|
for (const channelId in queueJson) {
|
||||||
let {teamsize} = queueJson[channelId] as queueInfoBase;
|
const {teamsize} = queueJson[channelId] as queueInfoBase;
|
||||||
if (teamsize)
|
if (teamsize !== 0)
|
||||||
QUEUE.set(channelId, { teamsize, players: [] })
|
QUEUE.set(channelId, { teamsize, players: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(e) {}
|
} catch(e) {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
function SaveQueue() {
|
function SaveQueue() {
|
||||||
|
|
||||||
let queueJson = Object.fromEntries(QUEUE),
|
const queueJson = Object.fromEntries(QUEUE),
|
||||||
queueFileJson: {[keys: string]: queueInfoBase} = {};
|
queueFileJson: {[keys: string]: queueInfoBase} = {};
|
||||||
|
|
||||||
for (let channelId of QUEUE.keys())
|
for (const channelId of QUEUE.keys())
|
||||||
queueFileJson[channelId] = { teamsize: queueJson[channelId].teamsize };
|
queueFileJson[channelId] = { teamsize: queueJson[channelId].teamsize };
|
||||||
|
|
||||||
fs.writeFileSync('./queues.json', JSON.stringify(queueFileJson, null, 2));
|
fs.writeFileSync('./queues.json', JSON.stringify(queueFileJson, null, 2));
|
||||||
@@ -40,17 +42,17 @@ function SaveQueue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function checkQueue(channel: TextChannel) {
|
async function checkQueue(channel: TextChannel) {
|
||||||
let info = QUEUE.get(channel.id);
|
const info = QUEUE.get(channel.id);
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (info.players.length >= info.teamsize) {
|
if (info.players.length >= info.teamsize) {
|
||||||
|
|
||||||
let team = info.players.splice(0, info.teamsize).map(m => m.toString());
|
const team = info.players.splice(0, info.teamsize).map(m => m.toString());
|
||||||
|
|
||||||
//TODO add embeds to lang.ts
|
//TODO add embeds to lang.ts
|
||||||
let embed = new MessageEmbed()
|
const embed = new MessageEmbed()
|
||||||
.setTitle('Team')
|
.setTitle('Team')
|
||||||
.setDescription(team.join('\n'));
|
.setDescription(team.join('\n'));
|
||||||
|
|
||||||
@@ -59,35 +61,33 @@ async function checkQueue(channel: TextChannel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
namespace Queue {
|
|
||||||
|
|
||||||
export function create(channelId: string, teamsize: number) {
|
|
||||||
if (!QUEUE.has(channelId)) {
|
export function queueCreate(channelId: string, teamsize: number) {
|
||||||
QUEUE.set(channelId, {teamsize, players: []});
|
if (!QUEUE.has(channelId)) {
|
||||||
SaveQueue();
|
QUEUE.set(channelId, {teamsize, players: []});
|
||||||
}
|
SaveQueue();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function remove(channelId: string) {
|
export function queueRemove(channelId: string) {
|
||||||
if (QUEUE.has(channelId)) {
|
if (QUEUE.has(channelId)) {
|
||||||
QUEUE.delete(channelId);
|
QUEUE.delete(channelId);
|
||||||
SaveQueue();
|
SaveQueue();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveQueue();
|
SaveQueue();
|
||||||
|
|
||||||
export async function discordInit(client: Client) {
|
export async function discordInit(client: Client) {
|
||||||
|
|
||||||
for (let channelId of QUEUE.keys()) {
|
for (const channelId of QUEUE.keys()) {
|
||||||
|
|
||||||
let info = QUEUE.get(channelId),
|
const info = QUEUE.get(channelId),
|
||||||
channel = await client.channels.fetch(channelId);
|
channel = await client.channels.fetch(channelId);
|
||||||
|
|
||||||
if (!info) { //no idea what could cause this but TS complains
|
if (!info) { //no idea what could cause this but TS complains
|
||||||
Queue.remove(channelId);
|
queueRemove(channelId);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ export async function discordInit(client: Client) {
|
|||||||
channelId,
|
channelId,
|
||||||
teamsize: info.teamsize
|
teamsize: info.teamsize
|
||||||
});
|
});
|
||||||
Queue.remove(channelId);
|
queueRemove(channelId);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,160 +105,155 @@ export async function discordInit(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
export namespace QueueCommands {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the queueInfo of an interaction
|
* get the queueInfo of an interaction
|
||||||
* @param interaction
|
* @param interaction
|
||||||
* @throws errorMessage class if it does not exist
|
* @throws errorMessage class if it does not exist
|
||||||
* @returns queue info
|
* @returns queue info
|
||||||
*/
|
*/
|
||||||
function getInfo(interaction: CommandInteraction): queueInfo {
|
function getInfo(interaction: CommandInteraction): queueInfo {
|
||||||
let info = QUEUE.get(interaction.channelId);
|
const info = QUEUE.get(interaction.channelId);
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
throw emsg('discord.noQueue');
|
throw emsg('discord.noQueue');
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* compiles all the get functions above
|
* compiles all the get functions above
|
||||||
* @param interaction
|
* @param interaction
|
||||||
* @throws if another get function throws
|
* @throws if another get function throws
|
||||||
* @returns object containing each
|
* @returns object containing each
|
||||||
*/
|
*/
|
||||||
const getAll = (interaction: CommandInteraction) => ({
|
const getAll = (interaction: CommandInteraction) => ({
|
||||||
member: getMember(interaction),
|
member: getMember(interaction),
|
||||||
channel: getChannel(interaction),
|
channel: getChannel(interaction),
|
||||||
info: getInfo(interaction)
|
info: getInfo(interaction)
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* checks if the interaction data is already in the queue
|
* checks if the interaction data is already in the queue
|
||||||
* @param interaction
|
* @param interaction
|
||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
export function queueContains(interaction: CommandInteraction): boolean {
|
export function queueContains(interaction: CommandInteraction): boolean {
|
||||||
|
|
||||||
let {member, info} = getAll(interaction);
|
const {member, info} = getAll(interaction);
|
||||||
|
|
||||||
if (info.players.map(m=>m.id).includes(member.id))
|
if (info.players.map(m=>m.id).includes(member.id))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a queue from an interaction
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be left
|
|
||||||
*/
|
|
||||||
export function queueCreate(interaction: CommandInteraction) {
|
|
||||||
memberIsModThrow(interaction);
|
|
||||||
|
|
||||||
let {channelId} = interaction,
|
|
||||||
teamsize = interaction.options.getInteger('teamsize', true);
|
|
||||||
|
|
||||||
let existing = QUEUE.get(channelId)
|
|
||||||
if (existing)
|
|
||||||
throw emsg(Lang.get('error.discord.noCreate', {
|
|
||||||
teamsize: existing.teamsize.toString()
|
|
||||||
}));
|
|
||||||
|
|
||||||
Queue.create(channelId, teamsize);
|
|
||||||
|
|
||||||
interaction.reply(Lang.get('discord.create', {
|
|
||||||
teamsize: teamsize.toString()
|
|
||||||
}))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* opens a queue
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be left
|
|
||||||
*/
|
|
||||||
export async function open(interaction: CommandInteraction) {
|
|
||||||
|
|
||||||
queueCreate(interaction);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* closes a queue
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be joined
|
|
||||||
*/
|
|
||||||
export async function close(interaction: CommandInteraction) {
|
|
||||||
memberIsModThrow(interaction);
|
|
||||||
|
|
||||||
QUEUE.delete(interaction.channelId);
|
|
||||||
|
|
||||||
await interaction.reply(Lang.get('discord.close'));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gives info about the queue
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be left
|
|
||||||
*/
|
|
||||||
export async function queue(interaction: CommandInteraction) {
|
|
||||||
|
|
||||||
let info = getInfo(interaction);
|
|
||||||
|
|
||||||
let embed = new MessageEmbed()
|
|
||||||
.setTitle('Active Queue')
|
|
||||||
.addField('Team Size', info.teamsize.toString(), true)
|
|
||||||
.addField('Players Joined', info.players.length.toString(), true)
|
|
||||||
.setFooter({text: 'type /join'}); //TODO
|
|
||||||
|
|
||||||
await interaction.reply({embeds: [embed], ephemeral: true});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* joins a queue
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be readied
|
|
||||||
*/
|
|
||||||
export async function join(interaction: CommandInteraction) {
|
|
||||||
|
|
||||||
let {member, info, channel} = getAll(interaction);
|
|
||||||
|
|
||||||
if (queueContains(interaction))
|
|
||||||
throw emsg('discord.inQueue');
|
|
||||||
|
|
||||||
info.players.push(member);
|
|
||||||
|
|
||||||
QUEUE.set(interaction.channelId, info);
|
|
||||||
|
|
||||||
await interaction.reply(Lang.get('discord.join'));
|
|
||||||
|
|
||||||
checkQueue(channel);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* leaves a queue
|
|
||||||
* @param interaction
|
|
||||||
* @throws errorMessage class if it cannot be reset
|
|
||||||
*/
|
|
||||||
export async function leave(interaction: CommandInteraction) {
|
|
||||||
|
|
||||||
let {member, info} = getAll(interaction);
|
|
||||||
|
|
||||||
if (!queueContains(interaction))
|
|
||||||
throw emsg('discord.notInQueue');
|
|
||||||
|
|
||||||
info.players.splice(info.players.indexOf(member), 1);
|
|
||||||
|
|
||||||
QUEUE.set(interaction.channelId, info);
|
|
||||||
|
|
||||||
await interaction.reply(Lang.get('discord.leave'));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* opens a queue
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be left
|
||||||
|
*/
|
||||||
|
function open(interaction: CommandInteraction) {
|
||||||
|
|
||||||
|
memberIsModThrow(interaction);
|
||||||
|
|
||||||
|
const {channelId} = interaction,
|
||||||
|
teamsize = interaction.options.getInteger('teamsize', true);
|
||||||
|
|
||||||
|
const existing = QUEUE.get(channelId);
|
||||||
|
if (existing)
|
||||||
|
throw emsg(Lang.get('error.discord.noCreate', {
|
||||||
|
teamsize: existing.teamsize.toString()
|
||||||
|
}));
|
||||||
|
|
||||||
|
queueCreate(channelId, teamsize);
|
||||||
|
|
||||||
|
interaction.reply(Lang.get('discord.create', {
|
||||||
|
teamsize: teamsize.toString()
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* closes a queue
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be joined
|
||||||
|
*/
|
||||||
|
async function close(interaction: CommandInteraction) {
|
||||||
|
memberIsModThrow(interaction);
|
||||||
|
|
||||||
|
QUEUE.delete(interaction.channelId);
|
||||||
|
|
||||||
|
await interaction.reply(Lang.get('discord.close'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gives info about the queue
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be left
|
||||||
|
*/
|
||||||
|
async function queue(interaction: CommandInteraction) {
|
||||||
|
|
||||||
|
const info = getInfo(interaction);
|
||||||
|
|
||||||
|
const embed = new MessageEmbed()
|
||||||
|
.setTitle('Active Queue')
|
||||||
|
.addField('Team Size', info.teamsize.toString(), true)
|
||||||
|
.addField('Players Joined', info.players.length.toString(), true)
|
||||||
|
.setFooter({text: 'type /join'}); //TODO
|
||||||
|
|
||||||
|
await interaction.reply({embeds: [embed], ephemeral: true});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* joins a queue
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be readied
|
||||||
|
*/
|
||||||
|
async function join(interaction: CommandInteraction) {
|
||||||
|
|
||||||
|
const {member, info, channel} = getAll(interaction);
|
||||||
|
|
||||||
|
if (queueContains(interaction))
|
||||||
|
throw emsg('discord.inQueue');
|
||||||
|
|
||||||
|
info.players.push(member);
|
||||||
|
|
||||||
|
QUEUE.set(interaction.channelId, info);
|
||||||
|
|
||||||
|
await interaction.reply(Lang.get('discord.join'));
|
||||||
|
|
||||||
|
checkQueue(channel);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* leaves a queue
|
||||||
|
* @param interaction
|
||||||
|
* @throws errorMessage class if it cannot be reset
|
||||||
|
*/
|
||||||
|
async function leave(interaction: CommandInteraction) {
|
||||||
|
|
||||||
|
const {member, info} = getAll(interaction);
|
||||||
|
|
||||||
|
if (!queueContains(interaction))
|
||||||
|
throw emsg('discord.notInQueue');
|
||||||
|
|
||||||
|
info.players.splice(info.players.indexOf(member), 1);
|
||||||
|
|
||||||
|
QUEUE.set(interaction.channelId, info);
|
||||||
|
|
||||||
|
await interaction.reply(Lang.get('discord.leave'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const QueueCommands = {
|
||||||
|
open,
|
||||||
|
close,
|
||||||
|
queue,
|
||||||
|
join,
|
||||||
|
leave
|
||||||
|
};
|
||||||
0
src/queueCommands.ts
Normal file
0
src/queueCommands.ts
Normal file
15
src/util.ts
15
src/util.ts
@@ -1,5 +1,5 @@
|
|||||||
import { CommandInteraction, GuildMember, TextChannel } from "discord.js";
|
import { CommandInteraction, GuildMember, TextChannel } from 'discord.js';
|
||||||
import { Lang } from "./lang";
|
import * as Lang from './lang';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shuffles an array
|
* shuffles an array
|
||||||
@@ -7,6 +7,7 @@ import { Lang } from "./lang";
|
|||||||
* @param array an array
|
* @param array an array
|
||||||
* @returns an array but shuffled
|
* @returns an array but shuffled
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function shuffle(array: any[]) {
|
export function shuffle(array: any[]) {
|
||||||
let currentIndex = array.length, randomIndex;
|
let currentIndex = array.length, randomIndex;
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ export class errorMessage {
|
|||||||
public msg: string;
|
public msg: string;
|
||||||
public ephemeral: boolean;
|
public ephemeral: boolean;
|
||||||
|
|
||||||
constructor(msg: string, ephemeral: boolean = true) {
|
constructor(msg: string, ephemeral = true) {
|
||||||
this.msg = msg;
|
this.msg = msg;
|
||||||
this.ephemeral = ephemeral;
|
this.ephemeral = ephemeral;
|
||||||
}
|
}
|
||||||
@@ -43,7 +44,7 @@ export class errorMessage {
|
|||||||
* @param ephemeral (default=true)
|
* @param ephemeral (default=true)
|
||||||
* @returns new errorMessage
|
* @returns new errorMessage
|
||||||
*/
|
*/
|
||||||
export const emsg = (msg: string, ephemeral: boolean = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral);
|
export const emsg = (msg: string, ephemeral = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ export interface queueInfo extends queueInfoBase{
|
|||||||
* @returns member
|
* @returns member
|
||||||
*/
|
*/
|
||||||
export function getMember(interaction: CommandInteraction): GuildMember {
|
export function getMember(interaction: CommandInteraction): GuildMember {
|
||||||
let member = interaction.member;
|
const member = interaction.member;
|
||||||
|
|
||||||
if (!(member instanceof GuildMember))
|
if (!(member instanceof GuildMember))
|
||||||
throw emsg('general.noMember');
|
throw emsg('general.noMember');
|
||||||
@@ -76,7 +77,7 @@ export function getMember(interaction: CommandInteraction): GuildMember {
|
|||||||
* @returns member
|
* @returns member
|
||||||
*/
|
*/
|
||||||
export function getChannel(interaction: CommandInteraction): TextChannel {
|
export function getChannel(interaction: CommandInteraction): TextChannel {
|
||||||
let channel = interaction.channel;
|
const channel = interaction.channel;
|
||||||
|
|
||||||
if (!(channel instanceof TextChannel))
|
if (!(channel instanceof TextChannel))
|
||||||
throw emsg('general.noChannel');
|
throw emsg('general.noChannel');
|
||||||
@@ -86,7 +87,7 @@ export function getChannel(interaction: CommandInteraction): TextChannel {
|
|||||||
|
|
||||||
|
|
||||||
export function memberIsMod(interaction: CommandInteraction): boolean {
|
export function memberIsMod(interaction: CommandInteraction): boolean {
|
||||||
let member = getMember(interaction);
|
const member = getMember(interaction);
|
||||||
return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES');
|
return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user