Merge pull request #23 from dmitmel/typescript

This commit is contained in:
Keanu Timmermans 2021-02-16 13:15:23 +01:00 committed by GitHub
commit 2ff732c927
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 48 deletions

View File

@ -124,14 +124,15 @@ export default new Command({
number: new Command({ number: new Command({
description: "Amount of messages to delete.", description: "Amount of messages to delete.",
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
if ($.channel.type === "dm") {
await $.channel.send("Can't clear messages in the DMs!");
return;
}
$.message.delete(); $.message.delete();
const fetched = await $.channel.messages.fetch({ const fetched = await $.channel.messages.fetch({
limit: $.args[0] limit: $.args[0]
}); });
$.channel await $.channel.bulkDelete(fetched);
/// @ts-ignore
.bulkDelete(fetched)
.catch((error: any) => $.channel.send(`Error: ${error}`));
} }
}) })
}), }),
@ -157,8 +158,7 @@ export default new Command({
permission: Command.PERMISSIONS.BOT_SUPPORT, permission: Command.PERMISSIONS.BOT_SUPPORT,
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
const nickName = $.args.join(" "); const nickName = $.args.join(" ");
const trav = $.guild?.members.cache.find((member) => member.id === $.client.user?.id); await $.guild?.me?.setNickname(nickName);
await trav?.setNickname(nickName);
if (botHasPermission($.guild, Permissions.FLAGS.MANAGE_MESSAGES)) if (botHasPermission($.guild, Permissions.FLAGS.MANAGE_MESSAGES))
$.message.delete({timeout: 5000}).catch($.handler.bind($)); $.message.delete({timeout: 5000}).catch($.handler.bind($));
$.channel.send(`Nickname set to \`${nickName}\``).then((m) => m.delete({timeout: 5000})); $.channel.send(`Nickname set to \`${nickName}\``).then((m) => m.delete({timeout: 5000}));

View File

@ -1,6 +1,4 @@
import {MessageEmbed, version as djsversion} from "discord.js"; import {MessageEmbed, version as djsversion} from "discord.js";
/// @ts-ignore
import {version} from "../../package.json";
import ms from "ms"; import ms from "ms";
import os from "os"; import os from "os";
import Command from "../core/command"; import Command from "../core/command";
@ -9,6 +7,8 @@ import {verificationLevels, filterLevels, regions, flags} from "../defs/info";
import moment from "moment"; import moment from "moment";
import utc from "moment"; import utc from "moment";
const {version} = require("../../package.json");
export default new Command({ export default new Command({
description: "Command to provide all sorts of info about the current server, a user, etc.", description: "Command to provide all sorts of info about the current server, a user, etc.",
run: "Please provide an argument.\nFor help, run `%prefix%help info`.", run: "Please provide an argument.\nFor help, run `%prefix%help info`.",
@ -36,13 +36,6 @@ export default new Command({
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
const core = os.cpus()[0]; const core = os.cpus()[0];
const embed = new MessageEmbed() const embed = new MessageEmbed()
.setThumbnail(
/// @ts-ignore
$.client.user?.displayAvatarURL({
dynamic: true,
size: 2048
})
)
.setColor($.guild?.me?.displayHexColor || "BLUE") .setColor($.guild?.me?.displayHexColor || "BLUE")
.addField("General", [ .addField("General", [
`** Client:** ${$.client.user?.tag} (${$.client.user?.id})`, `** Client:** ${$.client.user?.tag} (${$.client.user?.id})`,
@ -71,6 +64,11 @@ export default new Command({
`\u3000 • Used: ${formatBytes(process.memoryUsage().heapUsed)}` `\u3000 • Used: ${formatBytes(process.memoryUsage().heapUsed)}`
]) ])
.setTimestamp(); .setTimestamp();
const avatarURL = $.client.user?.displayAvatarURL({
dynamic: true,
size: 2048
});
if (avatarURL) embed.setThumbnail(avatarURL);
$.channel.send(embed); $.channel.send(embed);
} }
}), }),
@ -78,10 +76,13 @@ export default new Command({
description: "Displays info about the current guild.", description: "Displays info about the current guild.",
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
if ($.guild) { if ($.guild) {
const members = await $.guild.members.fetch({
withPresences: true,
force: true
});
const roles = $.guild.roles.cache const roles = $.guild.roles.cache
.sort((a, b) => b.position - a.position) .sort((a, b) => b.position - a.position)
.map((role) => role.toString()); .map((role) => role.toString());
const members = $.guild.members.cache;
const channels = $.guild.channels.cache; const channels = $.guild.channels.cache;
const emojis = $.guild.emojis.cache; const emojis = $.guild.emojis.cache;
const iconURL = $.guild.iconURL({dynamic: true}); const iconURL = $.guild.iconURL({dynamic: true});
@ -145,7 +146,7 @@ export default new Command({
description: "Displays info about mentioned user.", description: "Displays info about mentioned user.",
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
// Transforms the User object into a GuildMember object of the current guild. // Transforms the User object into a GuildMember object of the current guild.
const member = $.guild?.members.resolve($.args[0]) ?? (await $.guild?.members.fetch($.args[0])); const member = await $.guild?.members.fetch($.args[0]);
if (!member) if (!member)
return $.channel.send( return $.channel.send(
@ -156,8 +157,7 @@ export default new Command({
.sort((a: {position: number}, b: {position: number}) => b.position - a.position) .sort((a: {position: number}, b: {position: number}) => b.position - a.position)
.map((role: {toString: () => any}) => role.toString()) .map((role: {toString: () => any}) => role.toString())
.slice(0, -1); .slice(0, -1);
// @ts-ignore - Discord.js' typings seem to be outdated here. According to their v12 docs, it's User.fetchFlags() instead of User.flags. const userFlags = (await member.user.fetchFlags()).toArray();
const userFlags = ((await member.user.fetchFlags()) as UserFlags).toArray();
const embed = new MessageEmbed() const embed = new MessageEmbed()
.setThumbnail(member.user.displayAvatarURL({dynamic: true, size: 512})) .setThumbnail(member.user.displayAvatarURL({dynamic: true, size: 512}))
@ -183,10 +183,7 @@ export default new Command({
`** Server Join Date:** ${moment(member.joinedAt).format("LL LTS")}`, `** Server Join Date:** ${moment(member.joinedAt).format("LL LTS")}`,
`** Hoist Role:** ${member.roles.hoist ? member.roles.hoist.name : "None"}`, `** Hoist Role:** ${member.roles.hoist ? member.roles.hoist.name : "None"}`,
`** Roles:** [${roles.length}]: ${ `** Roles:** [${roles.length}]: ${
roles.length == 0 ? "None" roles.length == 0 ? "None" : roles.length <= 10 ? roles.join(", ") : trimArray(roles).join(", ")
: roles.length <= 10
? roles.join(", ")
: trimArray(roles).join(", ")
}` }`
]); ]);
$.channel.send(embed); $.channel.send(embed);

View File

@ -9,15 +9,14 @@ export default new Command({
if (!voiceChannel) return $.channel.send("You are not in a voice channel."); if (!voiceChannel) return $.channel.send("You are not in a voice channel.");
if (!$.guild?.me?.hasPermission("MANAGE_CHANNELS")) if (!voiceChannel.guild.me?.hasPermission("MANAGE_CHANNELS"))
return $.channel.send("I am lacking the required permissions to perform this action."); return $.channel.send("I am lacking the required permissions to perform this action.");
if ($.args.length === 0) return $.channel.send("Please provide a new voice channel name."); if ($.args.length === 0) return $.channel.send("Please provide a new voice channel name.");
const changeVC = $.guild.channels.resolve(voiceChannel.id); const prevName = voiceChannel.name;
$.channel const newName = $.args.join(" ");
.send(`Changed channel name from "${voiceChannel}" to "${$.args.join(" ")}".`) await voiceChannel.setName(newName);
/// @ts-ignore await $.channel.send(`Changed channel name from "${prevName}" to "${newName}".`);
.then(changeVC?.setName($.args.join(" ")));
} }
}); });

View File

@ -182,12 +182,16 @@ export async function loadCommands(): Promise<Collection<string, Command>> {
if (cmd.isDirectory()) { if (cmd.isDirectory()) {
if (cmd.name === "subcommands") continue; if (cmd.name === "subcommands") continue;
else $.warn(`You can't have multiple levels of directories! From: "dist/commands/${cmd.name}"`); else $.warn(`You can't have multiple levels of directories! From: "dist/commands/${cmd.name}"`);
} else loadCommand(cmd.name, list, selected.name); } else if (cmd.name.endsWith(".js")) {
loadCommand(cmd.name, list, selected.name);
}
} }
subdir.close(); subdir.close();
categories.set(category, list); categories.set(category, list);
} else loadCommand(selected.name, listMisc); } else if (selected.name.endsWith(".js")) {
loadCommand(selected.name, listMisc);
}
} }
dir.close(); dir.close();
@ -236,7 +240,7 @@ export default new Command({
permission: null, permission: null,
aliases: [], aliases: [],
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
}, },
subcommands: { subcommands: {
layer: new Command({ layer: new Command({
@ -246,7 +250,7 @@ export default new Command({
permission: null, permission: null,
aliases: [], aliases: [],
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
} }
}) })
}, },
@ -256,7 +260,7 @@ export default new Command({
usage: '', usage: '',
permission: null, permission: null,
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
} }
}), }),
number: new Command({ number: new Command({
@ -265,7 +269,7 @@ export default new Command({
usage: '', usage: '',
permission: null, permission: null,
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
} }
}), }),
any: new Command({ any: new Command({
@ -274,7 +278,7 @@ export default new Command({
usage: '', usage: '',
permission: null, permission: null,
async run($: CommonLibrary): Promise<any> { async run($: CommonLibrary): Promise<any> {
} }
}) })
});`; });`;

View File

@ -172,7 +172,7 @@ export function formatUTCTimestamp(now = new Date()) {
} }
export function botHasPermission(guild: Guild | null, permission: number): boolean { export function botHasPermission(guild: Guild | null, permission: number): boolean {
return !!(client.user && guild?.members.resolve(client.user)?.hasPermission(permission)); return !!guild?.me?.hasPermission(permission);
} }
export function updateGlobalEmoteRegistry(): void { export function updateGlobalEmoteRegistry(): void {
@ -216,20 +216,22 @@ $.paginate = async (
callback(page); callback(page);
}; };
const BACKWARDS_EMOJI = "⬅️";
const FORWARDS_EMOJI = "➡️";
const handle = (emote: string, reacterID: string) => { const handle = (emote: string, reacterID: string) => {
switch (emote) { switch (emote) {
case "⬅️": case BACKWARDS_EMOJI:
turn(-1); turn(-1);
break; break;
case "➡️": case FORWARDS_EMOJI:
turn(1); turn(1);
break; break;
} }
}; };
// Listen for reactions and call the handler. // Listen for reactions and call the handler.
await message.react("⬅️"); let backwardsReaction = await message.react(BACKWARDS_EMOJI);
await message.react("➡️"); let forwardsReaction = await message.react(FORWARDS_EMOJI);
eventListeners.set(message.id, handle); eventListeners.set(message.id, handle);
await message.awaitReactions( await message.awaitReactions(
(reaction, user) => { (reaction, user) => {
@ -248,8 +250,8 @@ $.paginate = async (
); );
// When time's up, remove the bot's own reactions. // When time's up, remove the bot's own reactions.
eventListeners.delete(message.id); eventListeners.delete(message.id);
message.reactions.cache.get("⬅️")?.users.remove(message.author); backwardsReaction.users.remove(message.author);
message.reactions.cache.get("➡️")?.users.remove(message.author); forwardsReaction.users.remove(message.author);
}; };
// Waits for the sender to either confirm an action or let it pass (and delete the message). // Waits for the sender to either confirm an action or let it pass (and delete the message).
@ -554,7 +556,6 @@ export abstract class GenericStructure {
public save(asynchronous = true) { public save(asynchronous = true) {
const tag = this.__meta__; const tag = this.__meta__;
/// @ts-ignore
delete this.__meta__; delete this.__meta__;
FileManager.write(tag, this, asynchronous); FileManager.write(tag, this, asynchronous);
this.__meta__ = tag; this.__meta__ = tag;

View File

@ -1,4 +1,4 @@
import {Client} from "discord.js"; import * as discord from "discord.js";
import setup from "./setup"; import setup from "./setup";
import {Config} from "./core/structures"; import {Config} from "./core/structures";
import {loadCommands} from "./core/command"; import {loadCommands} from "./core/command";
@ -6,9 +6,37 @@ import {loadEvents} from "./core/event";
import "discord.js-lavalink-lib"; import "discord.js-lavalink-lib";
import LavalinkMusic from "discord.js-lavalink-lib"; import LavalinkMusic from "discord.js-lavalink-lib";
declare module "discord.js" {
interface Presence {
patch(data: any): void;
}
}
// The terrible hacks were written by none other than The Noble Programmer On The White PC.
// NOTE: Terrible hack ahead!!! In order to reduce the memory usage of the bot
// we only store the information from presences that we actually end up using,
// which currently is only the (online/idle/dnd/offline/...) status (see
// `src/commands/info.ts`). What data is retrieved from the `data` object
// (which contains the data received from the Gateway) and how can be seen
// here:
// <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/structures/Presence.js#L81-L110>.
const oldPresencePatch = discord.Presence.prototype.patch;
discord.Presence.prototype.patch = function patch(data: any) {
oldPresencePatch.call(this, {status: data.status});
};
// This is here in order to make it much less of a headache to access the client from other files. // This is here in order to make it much less of a headache to access the client from other files.
// This of course won't actually do anything until the setup process is complete and it logs in. // This of course won't actually do anything until the setup process is complete and it logs in.
export const client = new Client(); export const client = new discord.Client();
// NOTE: Terrible hack continued!!! Unfortunately we can't receive the presence
// data at all when the GUILD_PRESENCES intent is disabled, so while we do
// waste network bandwidth and the CPU time for decoding the incoming packets,
// the function which handles those packets is NOP-ed out, which, among other
// things, skips the code which caches the referenced users in the packet. See
// <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/client/actions/PresenceUpdate.js#L7-L41>.
(client["actions"] as any)["PresenceUpdate"].handle = () => {};
(client as any).music = LavalinkMusic(client, { (client as any).music = LavalinkMusic(client, {
lavalink: { lavalink: {

View File

@ -2,7 +2,7 @@
"compilerOptions": { "compilerOptions": {
"rootDir": "src", "rootDir": "src",
"outDir": "dist", "outDir": "dist",
"target": "ES6", "target": "es2019",
"module": "CommonJS", "module": "CommonJS",
"moduleResolution": "node", "moduleResolution": "node",
"esModuleInterop": true, "esModuleInterop": true,
@ -11,7 +11,8 @@
"strictNullChecks": true, "strictNullChecks": true,
"strictFunctionTypes": true, "strictFunctionTypes": true,
"strictPropertyInitialization": true, "strictPropertyInitialization": true,
"removeComments": true "removeComments": true,
"sourceMap": true
}, },
"exclude": ["test"] "exclude": ["test"]
} }