Compare commits

..

No commits in common. "a3c7d1fef64a3abbdf8316ea57af7ce4a30af735" and "11c1c5640e75d5edd8bd6264940158e93f2b4448" have entirely different histories.

13 changed files with 123 additions and 102 deletions

View file

@ -57,7 +57,7 @@ If you want to contribute, feel free to fork this repo and making a pull request
## TODO
* [ ] Refactor [tictactoe](./helpers/tictactoe.js).
* [ ] Finish and release *dashboard-core* submodule.
* [ ] Rewrite dashboard.
## License

View file

@ -6,20 +6,4 @@ export default class IDatabaseAdapter {
async disconnect() {
throw new Error("Method `disconnect` not implemented.");
}
async find() {
throw new Error("Method \"find\" must be implemented");
}
async findOne() {
throw new Error("Method \"findOne\" must be implemented");
}
async updateOne() {
throw new Error("Method \"updateOne\" must be implemented");
}
async deleteOne() {
throw new Error("Method \"deleteOne\" must be implemented");
}
}

View file

@ -29,20 +29,4 @@ export default class MongooseAdapter extends IDatabaseAdapter {
await mongoose.disconnect();
logger.warn("Database disconnected.");
}
async find(model, query = {}, options = {}) {
return model.find(query, null, options).exec();
}
async findOne(model, query = {}, options = {}) {
return model.findOne(query, null, options).exec();
}
async updateOne(model, filter, update, options = {}) {
return model.updateOne(filter, update, options).exec();
}
async deleteOne(model, filter) {
return model.deleteOne(filter).exec();
}
}

View file

@ -0,0 +1,92 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js"),
{ QueryType } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand"),
fs = require("fs");
class Clips extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("clips")
.setDescription(client.translate("music/clips:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("music/clips:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/clips:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.addStringOption(option =>
option
.setName("query")
.setDescription(client.translate("music/clips:QUERY"))
.setDescriptionLocalizations({
uk: client.translate("music/clips:QUERY", null, "uk-UA"),
ru: client.translate("music/clips:QUERY", null, "ru-RU"),
})
.setRequired(true)
.setAutocomplete(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply();
const query = interaction.options.getString("query"),
voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true });
const perms = voice.permissionsFor(client.user);
if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.error("music/play:VOICE_CHANNEL_CONNECT", null, { edit: true });
client.player.play(interaction.member.voice.channel, query, {
nodeOptions: {
metadata: interaction,
},
searchEngine: QueryType.FILE,
selfDeaf: true,
leaveOnEnd: false,
leaveOnStop: true,
skipOnNoStream: true,
bufferingTimeout: 1000,
});
interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", {
songName: query.substring(8, query.length - 4),
}),
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").AutocompleteInteraction} interaction
* @returns
*/
async autocompleteRun(client, interaction) {
const query = interaction.options.getString("query"),
files = fs.readdirSync("./clips"),
results = files.filter(f => f.includes(query));
return await interaction.respond(
results.slice(0, 25).map(file => ({
name: file.substring(0, file.length - 4),
value: `./clips/${file}`,
})),
);
}
}
module.exports = Clips;

View file

@ -1,26 +1,4 @@
import path from "node:path";
import { GatewayIntentBits } from "discord.js";
import { AsyncLocalStorage } from "node:async_hooks";
export const PROJECT_ROOT = path.join(import.meta.dirname, "..");
export const CONFIG_PATH = path.join(PROJECT_ROOT, "..", "config.json");
export const CLIENT_INTENTS = [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildModeration,
GatewayIntentBits.GuildEmojisAndStickers,
GatewayIntentBits.GuildIntegrations,
GatewayIntentBits.GuildInvites,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildPresences,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildMessageTyping,
GatewayIntentBits.MessageContent,
GatewayIntentBits.DirectMessageTyping,
GatewayIntentBits.DirectMessages,
GatewayIntentBits.DirectMessageReactions,
];
export const CLIENT_ALLOWED_MENTIONS = { parse: ["everyone", "roles", "users"] };
export const SUPER_CONTEXT = new AsyncLocalStorage();

View file

@ -38,6 +38,7 @@ class Ready extends BaseEvent {
`I'm in ${servers} ${client.functions.getNoun(servers, client.translate("misc:NOUNS:SERVER:1"), client.translate("misc:NOUNS:SERVER:2"), client.translate("misc:NOUNS:SERVER:5"))}!`,
`Cached ${users} ${client.functions.getNoun(users, client.translate("misc:NOUNS:USERS:1"), client.translate("misc:NOUNS:USERS:2"), client.translate("misc:NOUNS:USERS:5"))}.`,
"Use /help for commands list!",
"Did you know that I have a brother called JaBa IT? Yeah! Ask Jonny about him.",
];
let i = 0;

View file

@ -1,6 +1,6 @@
import { resolve } from "node:path";
import logger from "../../helpers/logger.js";
import useClient from "../../utils/use-client.js";
import { client } from "../../index.js";
import { getFilePaths } from "../../utils/index.js";
import { toFileURL } from "../../utils/resolve-file.js";
import registerCommands from "./functions/registerCommands.js";
@ -8,7 +8,6 @@ import registerCommands from "./functions/registerCommands.js";
export const commands = [];
export const init = async () => {
const client = useClient();
await buildCommands();
await registerCommands({
@ -18,7 +17,6 @@ export const init = async () => {
};
const buildCommands = async () => {
const client = useClient();
const cmdPath = resolve(client.configService.get("paths.commands"));
const commandFilePaths = (await getFilePaths(cmdPath, true)).filter(path => path.endsWith(".js"));

View file

@ -1,9 +1,8 @@
import { resolve } from "node:path";
import logger from "../../helpers/logger.js";
import useClient from "../../utils/use-client.js";
import { client } from "../../index.js";
import { getFilePaths } from "../../utils/index.js";
import { toFileURL } from "../../utils/resolve-file.js";
import { useMainPlayer } from "discord-player";
export const events = [];
@ -13,7 +12,6 @@ export const init = async () => {
};
const buildEvents = async () => {
const client = useClient();
try {
const eventPath = resolve(client.configService.get("paths.events"));
const eventFilePaths = (await getFilePaths(eventPath, true)).filter(path => path.endsWith(".js"));
@ -39,10 +37,7 @@ const buildEvents = async () => {
};
const registerEvents = async () => {
const client = useClient();
const player = useMainPlayer();
for (const { data, run } of events) {
if (data.player) player.events.on(data.name, run);
if (data.once) client.once(data.name, run);
else client.on(data.name, run);
}

View file

@ -1,10 +1,26 @@
import { GatewayIntentBits } from "discord.js";
import { ExtendedClient } from "./structures/client.js";
import logger from "./helpers/logger.js";
import { CLIENT_INTENTS, CLIENT_ALLOWED_MENTIONS } from "./constants/index.js";
const client = new ExtendedClient({
intents: CLIENT_INTENTS,
allowedMentions: CLIENT_ALLOWED_MENTIONS,
export const client = new ExtendedClient({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildModeration,
GatewayIntentBits.GuildEmojisAndStickers,
GatewayIntentBits.GuildIntegrations,
GatewayIntentBits.GuildInvites,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildPresences,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildMessageTyping,
GatewayIntentBits.MessageContent,
GatewayIntentBits.DirectMessageTyping,
GatewayIntentBits.DirectMessages,
GatewayIntentBits.DirectMessageReactions,
],
allowedMentions: { parse: ["everyone", "roles", "users"] },
});
client.init();
@ -12,7 +28,7 @@ client.init();
client
.on("disconnect", () => logger.warn("Bot disconnected."))
.on("reconnecting", () => logger.warn("Bot reconnecting..."))
.on("warn", logger.log)
.on("error", logger.log);
.on("warn", console.log)
.on("error", console.log);
process.on("unhandledRejection", logger.log).on("uncaughtException", logger.log);
process.on("unhandledRejection", console.log).on("uncaughtException", console.log);

View file

@ -1,7 +1,5 @@
import { model, Schema } from "mongoose";
import useClient from "../utils/use-client.js";
const client = useClient();
import { client } from "../index.js";
export default model(
"Guild",

View file

@ -1,29 +1,21 @@
import { Client } from "discord.js";
import { Player } from "discord-player";
import MongooseAdapter from "../adapters/database/MongooseAdapter.js";
import { init as initCommands } from "../handlers/command-handler/index.js";
import { init as initEvents } from "../handlers/event-handler/index.js";
import logger from "../helpers/logger.js";
import ConfigService from "../services/config/index.js";
import InternationalizationService from "../services/languages/index.js";
import { SUPER_CONTEXT } from "../constants/index.js";
export class ExtendedClient extends Client {
/**
* @param {import("discord.js").ClientOptions} options
*/
constructor(options) {
if (SUPER_CONTEXT.getStore()) {
return SUPER_CONTEXT.getStore();
}
super(options);
this.configService = new ConfigService();
this.adapter = new MongooseAdapter(this.configService.get("mongoDB"));
this.i18n = new InternationalizationService(this);
new Player(this);
SUPER_CONTEXT.enterWith(this);
}
async init() {

View file

@ -1,15 +1,14 @@
import { EmbedBuilder } from "discord.js";
import useClient from "../utils/use-client.js";
import { client } from "../index.js";
/**
*
* @param {import("discord.js").EmbedData} data - embed data
* @returns The generated EmbedBuilder instance.
*/
export const createEmbed = data => {
const client = useClient();
export const createEmbed = data =>
new EmbedBuilder({
footer: typeof data.footer === "object" ? data.footer : data.footer ? { text: data.footer } : client.configService.get("embed.footer"),
color: data.color ?? client.configService.get("embed.color"),
...data,
});
};

View file

@ -1,16 +0,0 @@
import { SUPER_CONTEXT } from "../constants/index.js";
/**
* Returns the instance of the client.
*
* @throws {Error} Client is not initialized. Please initialize it first.
*
* @returns {import("../structures/client.js").ExtendedClient} The client instance.
*/
export default function useClient() {
const store = SUPER_CONTEXT.getStore();
if (!store) {
throw new Error("Client is not initialized. Please initialize it first.");
}
return store;
}