This commit is contained in:
Jonny_Bro (Nikita) 2024-04-07 15:29:16 +05:00
parent 07658d64d2
commit b1d1c5a0ab
Signed by: jonny_bro
GPG key ID: 3F1ECC04147E9BD8
12 changed files with 230 additions and 78 deletions

View file

@ -81,7 +81,11 @@ class JaBaClient extends Client {
}
/**
* Logins into the account and connects to the database
* Initializes the client by logging in with the provided token and connecting to the MongoDB database.
*
* This method is called during the client's startup process to set up the necessary connections and resources.
*
* @returns {Promise<void>} A Promise that resolves when the client is fully initialized.
*/
async init() {
this.login(this.config.token);
@ -100,8 +104,14 @@ class JaBaClient extends Client {
}
/**
* Loads all commands from directory
* @param {String} dir Directory where commands are located
* Loads all the commands from the specified directory and registers them with the Discord API.
*
* This method is responsible for dynamically loading all the command files from the specified directory,
* creating instances of the corresponding command classes, and registering the commands with the Discord API.
* It also handles any additional setup or initialization required by the loaded commands.
*
* @param {string} dir - The directory path where the command files are located.
* @returns {Promise<void>} A Promise that resolves when all the commands have been loaded and registered.
*/
async loadCommands(dir) {
const rest = new REST().setToken(this.config.token),
@ -147,17 +157,19 @@ class JaBaClient extends Client {
}
/**
* @returns {String} Bot's default language
* Returns the default language from the list of available languages.
* @returns {Language} The default language.
*/
get defaultLanguage() {
return this.languages.find(language => language.default);
}
/**
* Translates from a key to language
* @param {String} key Key
* @param {Array} args Arguments for translation
* @param {String} locale Language
* Translates a key using the specified locale, or the default language if no locale is provided.
* @param {string} key The translation key to look up.
* @param {any[]} args Any arguments to pass to the translation function.
* @param {string} [locale=this.defaultLanguage.name] The locale to use for the translation. Defaults to the default language.
* @returns {string} The translated string.
*/
translate(key, args, locale = this.defaultLanguage.name) {
const lang = this.translations.get(locale);
@ -166,9 +178,19 @@ class JaBaClient extends Client {
}
/**
* Returns an embed created from given data
* @param {Object} data Data for embed
* @returns {import("discord.js").Embed}
* Generates an EmbedBuilder instance with the provided data.
* @param {Object} data - The data to use for the embed.
* @param {string} [data.title] - The title of the embed.
* @param {string} [data.description] - The description of the embed.
* @param {string} [data.thumbnail] - The URL of the thumbnail image for the embed.
* @param {Object[]} [data.fields] - An array of field objects for the embed.
* @param {string} [data.image] - The URL of the image for the embed.
* @param {string} [data.url] - The URL to be used as the embed's hyperlink.
* @param {number} [data.color] - The color of the embed's border. If not provided, the default color from the client's configuration will be used.
* @param {string} [data.footer] - The text to be displayed as the embed's footer. If not provided, the default footer from the client's configuration will be used.
* @param {Date} [data.timestamp] - The timestamp to be displayed in the embed's footer. If not provided, the current timestamp will be used.
* @param {string|Object} [data.author] - The author information for the embed. Can be a string (name) or an object with `name` and/or `iconURL` properties.
* @returns {EmbedBuilder} The generated EmbedBuilder instance.
*/
embed(data) {
const embed = new EmbedBuilder()
@ -193,16 +215,16 @@ class JaBaClient extends Client {
if (!data.author || data.author === null) embed.setAuthor(null);
else if (typeof data.author === "string") embed.setAuthor({ name: data.author, iconURL: this.user.avatarURL() });
else if (typeof data.author === "object" && (data.author.iconURL !== null || data.author.iconURL !== undefined)) embed.setAuthor({ name: data.author.name, iconURL: this.user.avatarURL() });
else if (typeof data.author === "object" && (data.author.iconURL !== null || data.author.iconURL !== undefined)) embed.setAuthor({ name: data.author.name, iconURL: data.author.iconURL });
else embed.setAuthor(data.author);
return embed;
}
/**
* Creates an invite link for guild
* @param {String} guildId Guild ID
* @returns {String} Invite link
* Creates an invite for the specified guild.
* @param {string} guildId - The ID of the guild to create the invite for.
* @returns {Promise<string>} The URL of the created invite, or an error message if no suitable channel was found or the bot lacks the necessary permissions.
*/
async createInvite(guildId) {
const guild = this.guilds.cache.get(guildId),
@ -213,9 +235,10 @@ class JaBaClient extends Client {
}
/**
* Loads a single command from directory
* @param {String} dir Directory where command is located
* @param {String} file Filename of the command
* Loads a command from the specified directory and file.
* @param {string} dir - The directory containing the command file.
* @param {string} file - The name of the command file (without the .js extension).
* @returns {Promise<string>} A log message indicating the successful loading of the command.
*/
async loadCommand(dir, file) {
const Command = require(path.join(dir, `${file}.js`));
@ -230,10 +253,10 @@ class JaBaClient extends Client {
}
/**
* Removes a command from cache
* @param {String} dir Directory where command is located
* @param {String} name Command name
* @returns
* Unloads a command from the specified directory and file.
* @param {string} dir - The directory containing the command file.
* @param {string} name - The name of the command file (without the .js extension).
* @returns {void} This method does not return a value.
*/
async unloadCommand(dir, name) {
delete require.cache[require.resolve(`${dir}${path.sep}${name}.js`)];
@ -242,8 +265,9 @@ class JaBaClient extends Client {
}
/**
* Loads all events from directory recursively
* @param {String} dir Directory where events are located
* Loads all event files from the specified directory and its subdirectories.
* @param {string} dir - The directory containing the event files.
* @returns {void} This method does not return a value.
*/
async loadEvents(dir) {
const filePath = path.join(__dirname, dir);
@ -270,9 +294,9 @@ class JaBaClient extends Client {
}
/**
* Finds or creates a user in the database
* @param {String} userID User ID
* @returns {Promise<import("./User")>} Mongoose model
* Finds or creates a user in the database based on the provided user ID.
* @param {string} userID - The ID of the user to find or create.
* @returns {Promise<Object>} The user data object, either retrieved from the database or newly created.
*/
async findOrCreateUser(userID) {
let userData = await this.usersData.findOne({ id: userID });
@ -293,9 +317,11 @@ class JaBaClient extends Client {
}
/**
* Finds or creates a guild's member in the database
* @param {Array} { id: Member ID, Guild ID }
* @returns {Promise<import("./Member")>} Mongoose model
* Finds or creates a member in the database based on the provided member ID and guild ID.
* @param {Object} options - The options for finding or creating the member.
* @param {string} options.id - The ID of the member to find or create.
* @param {string} options.guildId - The ID of the guild the member belongs to.
* @returns {Promise<Object>} The member data object, either retrieved from the database or newly created.
*/
async findOrCreateMember({ id: memberID, guildId }) {
let memberData = await this.membersData.findOne({ guildID: guildId, id: memberID });
@ -324,9 +350,9 @@ class JaBaClient extends Client {
}
/**
* Finds or creates guild in DB
* @param {String} guildId Guild ID
* @returns {Promise<import("./Guild")>} Mongoose model
* Finds or creates a guild in the database based on the provided guild ID.
* @param {string} guildId - The ID of the guild to find or create.
* @returns {Promise<Object>} The guild data object, either retrieved from the database or newly created.
*/
async findOrCreateGuild(guildId) {
let guildData = await this.guildsData.findOne({ id: guildId }).populate("members");

View file

@ -91,11 +91,11 @@ class Poll extends BaseCommand {
author: interaction.translate("moderation/poll:TITLE"),
fields: [
{
name: "\u200b",
name: "\u200B",
value: question,
},
{
name: "\u200b",
name: "\u200B",
value: interaction.translate("moderation/poll:REACT", {
success: cool.toString(),
error: notcool.toString(),

View file

@ -278,7 +278,7 @@ async function updateEmbed(interaction, queue) {
value: progressBar,
},
{
name: "\u200b",
name: "\u200B",
value: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[mode]}\``,
},
],

View file

@ -0,0 +1,90 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
class Courses extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("courses")
.setDescription(client.translate("beatrun.ru/courses:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("beatrun.ru/courses:DESCRIPTION", null, "uk-UA"),
ru: client.translate("beatrun.ru/courses:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.addStringOption(option =>
option
.setName("code")
.setDescription(client.translate("common:CODE"))
.setDescriptionLocalizations({
uk: client.translate("common:CODE", null, "uk-UA"),
ru: client.translate("common:CODE", null, "ru-RU"),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction) {
await interaction.deferReply();
const code = interaction.options.getString("code");
const response = await fetch(`https://courses.beatrun.ru/api/stats/${code}`).then(res => res.json());
if (response.res === 401) return interaction.error("beatrun.ru/courses:NOT_FOUND", null, { ephemeral: true, edit: true });
const embed = client.embed({
title: code,
description: `[${interaction.translate("beatrun.ru/courses:DOWNLOAD")}](https://courses.beatrun.ru/${response.course.path})`,
thumbnail: response.course.mapimg,
url: `https://courses.beatrun.ru/?search=${code}`,
fields: [
{
name: interaction.translate("beatrun.ru/courses:MAP"),
value: `[${response.course.map}](https://steamcommunity.com/sharedfiles/filedetails/?id=${response.course.mapid})`,
inline: true,
},
{
name: interaction.translate("beatrun.ru/courses:UPLOADER"),
value: `[${response.course.uploader.name}](https://steamcommunity.com/profiles/${response.course.uploader.userid})`,
inline: true,
},
{
name: "\u200B",
value: "\u200B",
inline: true,
},
{
name: interaction.translate("beatrun.ru/courses:DATE"),
value: `<t:${Math.floor(response.course.time / 1000)}:D>`,
inline: true,
},
{
name: interaction.translate("beatrun.ru/courses:PLAYS"),
value: `${response.course.plays || 0}`,
inline: true,
},
],
});
interaction.editReply({
embeds: [embed],
});
}
}
module.exports = Courses;

View file

@ -1,18 +1,12 @@
const moment = require("moment");
moment.relativeTimeThreshold("ss", 5);
moment.relativeTimeThreshold("s", 60);
moment.relativeTimeThreshold("m", 60);
moment.relativeTimeThreshold("h", 60);
moment.relativeTimeThreshold("d", 24);
moment.relativeTimeThreshold("M", 12);
module.exports = {
/**
* Calls a Callback for Each Element in Collection Asynchronously
* @param {Array} collection Collection
* @param {Function} callback Function to Perform on Collection
* @returns {Promise}
* Asynchronously iterates over a collection and executes a callback function for each item.
*
* @param {any[]} collection - The collection to iterate over.
* @param {(item: any) => Promise<void>} callback - The async callback function to execute for each item in the collection.
* @returns {Promise<void>} A promise that resolves when all items in the collection have been processed.
*/
async asyncForEach(collection, callback) {
const allPromises = collection.map(async key => {
@ -23,10 +17,11 @@ module.exports = {
},
/**
* Sorts an Array by Key
* @param {Array} array Array to Sort
* @param {Number} key Key
* @returns {Array} Sorted Array
* Sorts an array by the specified key in ascending order.
*
* @param {any[]} array - The array to sort.
* @param {string} key - The key to sort the array by.
* @returns {any[]} The sorted array.
*/
sortByKey(array, key) {
return array.sort(function (a, b) {
@ -37,9 +32,10 @@ module.exports = {
},
/**
* Shuffles the Array
* @param {Array} pArray Array to Shuffle
* @returns {Array} Shuffled Array
* Shuffles the elements of the provided array in-place.
*
* @param {any[]} pArray - The array to shuffle.
* @returns {any[]} The shuffled array.
*/
shuffle(pArray) {
const array = [];
@ -63,10 +59,11 @@ module.exports = {
},
/**
* Returns a Random Number Between min (inclusive) And max (inclusive)
* @param {Number} min Min value (inclusive)
* @param {Number} max Max value (inclusive)
* @returns {Number} Integer
* Generates a random integer between the specified minimum and maximum values (inclusive).
*
* @param {number} min - The minimum value (inclusive).
* @param {number} max - The maximum value (inclusive).
* @returns {number} A random integer between min and max.
*/
randomNum(min, max) {
min = Math.ceil(min);
@ -76,12 +73,13 @@ module.exports = {
},
/**
* Beautifies the given Date
* @param {import("../base/Client")} client Discord Client
* @param {Date} date Date
* @param {String | null} format Format for Moment
* @param {String} locale Language
* @returns {String} Beautified Date
* Formats a date for the specified client and locale.
*
* @param {Object} client - The client object containing language data.
* @param {string} date - The date to format.
* @param {string} [format=null] - The date format to use. If not provided, the default format for the client's language will be used.
* @param {string} [locale=client.defaultLanguage.name] - The locale to use for formatting the date.
* @returns {string} The formatted date.
*/
printDate(client, date, format = null, locale = client.defaultLanguage.name) {
const languageData = client.languages.find(language => language.name === locale);
@ -91,13 +89,14 @@ module.exports = {
},
/**
* Converts the Given Time
* @param {import("../base/Client")} client Discord Client
* @param {String} time Time
* @param {Boolean} type Type (To now = true or from now = false)
* @param {Boolean} prefix Include Prefix
* @param {String} locale Language
* @returns {String} Time
* Formats a time value relative to the current time.
*
* @param {Object} client - The client object containing language data.
* @param {string|number|Date} time - The time value to format.
* @param {boolean} [type=false] - If true, formats the time as "X time ago", otherwise formats it as "in X time".
* @param {boolean} [prefix=true] - If true, includes a prefix like "in" or "ago" in the formatted time.
* @param {string} [locale=client.defaultLanguage.name] - The locale to use for formatting the time.
* @returns {string} The formatted time value.
*/
convertTime(client, time, type = false, prefix = true, locale = client.defaultLanguage.name) {
const languageData = client.languages.find(language => language.name === locale);
@ -107,12 +106,13 @@ module.exports = {
},
/**
* Get a Noun for Number
* @param {Number} number Number
* @param {String} one String for one
* @param {String} two String for two
* @param {String} five String for five
* @returns
* Generates the appropriate noun form based on the given number and noun forms.
*
* @param {number} number - The number to use for determining the noun form.
* @param {string} one - The noun form for the singular case.
* @param {string} two - The noun form for the dual case.
* @param {string} five - The noun form for the plural case.
* @returns {string} The appropriate noun form based on the given number.
*/
getNoun(number, one, two, five) {
let n = Math.abs(number);

View file

@ -0,0 +1,11 @@
{
"DESCRIPTION": "Get course info",
"USAGE": "",
"EXAMPLES": "courses code:ABCD-XZYX-1234",
"NOT_FOUND": "Course not found",
"MAP": "Map",
"UPLOADER": "Uploaded by",
"DATE": "Upload date",
"PLAYS": "Plays",
"DOWNLOAD": "Download"
}

View file

@ -9,6 +9,7 @@
"CANCEL": "Cancel",
"CHANNEL": "Channel",
"CHANNELS": "Channels",
"CODE": "Code",
"COLOR": "Color",
"CONTENT": "Content",
"COMMAND": "Command",

View file

@ -0,0 +1,11 @@
{
"DESCRIPTION": "Получить информацию о курсе",
"USAGE": "",
"EXAMPLES": "courses code:ABCD-XZYX-1234",
"NOT_FOUND": "Курс не найден",
"MAP": "Карта",
"UPLOADER": "Загрузил",
"DATE": "Дата загрузки",
"PLAYS": "Сыграно",
"DOWNLOAD": "Скачать"
}

View file

@ -9,6 +9,7 @@
"CANCEL": "Отменить",
"CHANNEL": "Канал",
"CHANNELS": "Каналы",
"CODE": "Код",
"COLOR": "Цвет",
"CONTENT": "Содержимое",
"COMMAND": "Команда",

View file

@ -0,0 +1,11 @@
{
"DESCRIPTION": "Отримати інформацію про курс",
"USAGE": "",
"EXAMPLES": "courses code:ABCD-XZYX-1234",
"NOT_FOUND": "Курс не знайдено",
"MAP": "Карта",
"UPLOADER": "Завантажив",
"DATE": "Дата завантаження",
"PLAYS": "Зіграно",
"DOWNLOAD": "Завантажити"
}

View file

@ -9,6 +9,7 @@
"CANCEL": "Скасувати",
"CHANNEL": "Канал",
"CHANNELS": "Канали",
"CODE": "Код",
"COLOR": "Колір",
"CONTENT": "Вміст",
"COMMAND": "Команда",

View file

@ -1,6 +1,6 @@
{
"name": "jaba",
"version": "4.4.4",
"version": "4.5.0",
"description": "My Discord Bot",
"main": "index.js",
"scripts": {