diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index be6c62d..a3d94a3 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -2,9 +2,6 @@ name: CI on: [push] -permissions: - contents: read - jobs: CI: runs-on: node @@ -16,6 +13,6 @@ jobs: with: node-version: 'latest' - name: install dependencies - run: npm ci + run: npm install - name: run tests - run: npm test + run: npm test \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..fa657a3 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,22 @@ +name: Lint Codebase + +on: [push] + +jobs: + eslint: + runs-on: node + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 'latest' + + - name: Install dependencies + run: npm install + + - name: Run ESLint + run: npm run lint \ No newline at end of file diff --git a/.github/workflows/njsscan.yml b/.github/workflows/njsscan.yml deleted file mode 100644 index ff888b4..0000000 --- a/.github/workflows/njsscan.yml +++ /dev/null @@ -1,42 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow integrates njsscan with GitHub's Code Scanning feature -# nodejsscan is a static security code scanner that finds insecure code patterns in your Node.js applications - -name: njsscan sarif - -on: - push: - branches: [ "master", "devbot" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "master", "devbot" ] - schedule: - - cron: '43 12 * * 6' - -permissions: - contents: read - -jobs: - njsscan: - permissions: - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - runs-on: ubuntu-latest - name: njsscan code scanning - steps: - - name: Checkout the code - uses: actions/checkout@v3 - - name: nodejsscan scan - id: njsscan - uses: ajinabraham/njsscan-action@v7 - with: - args: '. --sarif --output results.sarif || true' - - name: Upload njsscan report - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: results.sarif diff --git a/README.md b/README.md index 1b33dd4..71b3e53 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ You can also change the global prefix. You should enter you discord user id, so you can use the admin commands. Every time you want to change something in this file, you have to restart the bot. -If the config is ever changed, you need to either delete it and repeat the steps above or take a look at the util/createInitialConfig.js file. +If the config is ever changed, you need to either delete it and repeat the steps above or take a look at the [util/createInitialConfig.js](./util/createInitialConfig.js) file. ## Known issues diff --git a/commands/admin/setPresence.js b/commands/admin/setPresence.js index 5dbfd51..bd6fe5f 100644 --- a/commands/admin/setPresence.js +++ b/commands/admin/setPresence.js @@ -1,4 +1,3 @@ -const savePresence = require("../../util/savePresence"); const setPresence = require("../../util/setPresence"); module.exports = { @@ -11,20 +10,12 @@ module.exports = { ,"Updates once a minute if custom variables are used." ,"" ,"Custom Variables:" - ,"${guilds},${prefix},${uptime},{members}"], + ,"${guilds},${prefix},${uptime}"], admin: true, - execute({message, client, args, prefix}) { - let forceUpdate = false; - if(args.length > 1 && args[0] === "force") { - forceUpdate = true; - args.shift(); - } - if(args.length < 1){ - message.channel.send(`You need at least two arguments for this command, see \`${prefix}help setpresence\``) - return; - } + execute({message, client, args, globalPrefix}) { + const savePresence = require("../../util/savePresence"); let presenceType = args[0].toLocaleUpperCase(); - let sendText = "Presence has been set."; + let sendText = "Updated presence"; switch (presenceType) { case "PLAY": @@ -55,11 +46,8 @@ module.exports = { const firstArg = args[0].length + 1; let temp = args.join(" "); let presenceText = temp.slice(firstArg, temp.length) + setPresence({presenceText: presenceText,presenceType: presenceType, client: client, globalPrefix: globalPrefix}); savePresence(presenceType, presenceText, client); - if(forceUpdate) - setPresence({presenceText, presenceType, client}) - else - sendText = `${sendText} It will update ` } message.channel.send(sendText); diff --git a/commands/admin/update.js b/commands/admin/update.js index 7c9a75f..7de9db0 100644 --- a/commands/admin/update.js +++ b/commands/admin/update.js @@ -1,5 +1,4 @@ const calculateReloaded = require("../../util/calculateReloaded"); -const executeCommand = require("../../util/executeCommand"); const reloadCommands = require("../../util/reloadCommands"); module.exports = { @@ -28,12 +27,10 @@ module.exports = { let commitCount = stdout.split(/\r\n|\r|\n/).length - 1 sendText = `${sendText}\n\nLatest commits (${commitCount}):\n${stdout}` if(sendText.length >= 2000){ - sendText = sendText.slice(1955) + sendText.slice(1955) sendText = `${sendText}\n... Message is too long to show everything` } message.channel.send(sendText) - const githash = executeCommand(`git`, ["rev-parse", "--short", "HEAD"]); - client.githash = githash.error ? "N/A" : githash.output; if (err) console.log(stderr) }) } diff --git a/commands/admin/whitelist.js b/commands/admin/whitelist.js deleted file mode 100644 index 327e3de..0000000 --- a/commands/admin/whitelist.js +++ /dev/null @@ -1,107 +0,0 @@ -const sqlite3 = require('sqlite3').verbose(); - -module.exports = { - name: 'whitelist', - description: 'Whitelist a command in a specific server, or for a user.', - admin: true, - async execute({message, args, prefix, client}) { - if(args.length < 3){ - message.channel.send(`You need to supply the command and guild that you want to whitelist\n\`${prefix}whitelist \``); - return; - } - let option = args[0]; - let command = args[1]; - let guildOrUser = args[2]; - - if(option === "guild" || option === "server"){ - if(guildOrUser === "this") guildOrUser = message.guild.id; - const whitelistedCommands = client.whitelist.guild.get(guildOrUser); - if(whitelistedCommands && whitelistedCommands.includes(command)){ - message.channel.send("Command is already whitelisted in that server.") - return; - } - // TODO: First check if the bot has access to that guild before whitelisting. - const databasePath = 'data/database.db' - const db = new sqlite3.Database(databasePath) - let err = false; - await new Promise((resolve, reject)=>{ - db.run(`INSERT INTO guild_whitelist ( - guildId, - command, - dateAdded - ) VALUES (?, ?, ?)`, - [ - guildOrUser, - command, - new Date().getTime() - ], function (error) { - if (error) { - console.error(error); - err = true; - resolve(); - }else{ - resolve(); - } - }); - }) - db.close(); - if(!err){ - if(whitelistedCommands){ - whitelistedCommands.push(command); - client.whitelist.guild.set(guildOrUser, whitelistedCommands); - }else { - client.whitelist.guild.set(guildOrUser, command); - } - message.channel.send(`"${command}" has been whitelisted in that server.`) - - } else message.channel.send("Could not whitelist the server with that command. Check the logs.") - return; - }else if (option === "user"){ - const whitelistedCommands = client.whitelist.user.get(guildOrUser); - if(whitelistedCommands && whitelistedCommands.includes(command)){ - message.channel.send("Command is already whitelisted for that user.") - return; - } - const databasePath = 'data/database.db' - const db = new sqlite3.Database(databasePath) - let err = false; - await new Promise((resolve, reject)=>{ - db.run(`INSERT INTO user_whitelist ( - userId, - command, - dateAdded - ) VALUES (?, ?, ?)`, - [ - guildOrUser, - command, - new Date().getTime() - ], function (error) { - if (error) { - console.error(error); - err = true; - resolve(); - }else{ - resolve(); - } - }); - }) - db.close(); - if(!err){ - if(whitelistedCommands){ - whitelistedCommands.push(command); - client.whitelist.user.set(guildOrUser, whitelistedCommands); - }else { - client.whitelist.user.set(guildOrUser, command); - } - message.channel.send(`"${command}" has been whitelisted for ${guildOrUser}.`) - - } else message.channel.send("Could not whitelist the server with that command. Check the logs.") - return; - } - - - - // TODO: Add ability to remove server from whitelist. - } - -}; \ No newline at end of file diff --git a/commands/info/botinfo.js b/commands/info/botinfo.js index b806459..df700bf 100644 --- a/commands/info/botinfo.js +++ b/commands/info/botinfo.js @@ -1,6 +1,6 @@ const {EmbedBuilder} = require('discord.js'); const getCreationDate = require('../../util/getCreationDate'); -const getGuildInfo = require('../../util/getGuildInfo'); +const getGuildCount = require('../../util/getGuildCount'); @@ -8,28 +8,15 @@ module.exports = { name: 'botinfo', description: 'Shows information about the bot', execute({message, client, prefix}) { - let guildInfo = getGuildInfo(client) - let descriptionArr = [`Name: ${client.user.username}`, - `Prefix: ${prefix}`, - `Total Servers: ${guildInfo.guildCount}`, - `Total Members: ${guildInfo.totalMembers} (${guildInfo.uniqueMemberCount} unique)`, - `Total Commands: ${client.commands.size}`, - `Creation Date: ${getCreationDate(client)}`, - `Source: [Click Here](https://github.com/SileNce5k/discord_bot)`, - `Current Version: ${client.githash}` - ] - - let description = ""; - descriptionArr.forEach(desc => { - description += `${desc}\n`; - }) - + let guildCount = getGuildCount(client) const embed = new EmbedBuilder() .setColor(15780145) .setTitle("Information about bot") .setTimestamp() .setAuthor({name: client.user.username, iconURL: client.user.avatarURL({ format: 'png', dynamic: true, size: 2048 })}) - .setDescription(description) + .addFields({ + name: "General info", value: `Name: ${client.user.username}\nPrefix: ${prefix}\nTotal Servers: ${guildCount}\nTotal Commands: ${client.commands.size}\nCreation Date: ${getCreationDate(client)}\nSource: [Click Here](https://github.com/SileNce5k/discord_bot)`, + },) message.channel.send({embeds :[embed]}) diff --git a/commands/info/guilds.js b/commands/info/guilds.js index 480fdda..c4eb45e 100644 --- a/commands/info/guilds.js +++ b/commands/info/guilds.js @@ -3,10 +3,10 @@ module.exports = { description: 'Returns guild names', admin: true, execute({message, client}) { - let guildNames = client.guilds.cache - .sort((a, b) => b.memberCount - a.memberCount) - .map(guild => `${guild.name} (${guild.memberCount} members)`) - .join("\n"); + let guildNames = ""; + client.guilds.cache.each(guild => { + guildNames = guildNames + guild.name + "\n"; + }); message.channel.send(guildNames) } }; \ No newline at end of file diff --git a/commands/info/help.js b/commands/info/help.js index da05e34..e88df47 100644 --- a/commands/info/help.js +++ b/commands/info/help.js @@ -1,4 +1,3 @@ -const fs = require('fs'); const {EmbedBuilder} = require('discord.js'); const getSubdirFiles = require('../../util/getSubdirFiles'); @@ -13,10 +12,10 @@ module.exports = { execute({ message, args, prefix, client }) { let commands = "" let commandFiles = getSubdirFiles('commands/') + let x = false; let fieldName = `Page [[page]]/${Math.round(client.commands.size / 10)}`; let iteration = 0; let num_in_args = false; - let added_commands = 0; let page = -1; @@ -31,6 +30,7 @@ module.exports = { fieldName = fieldName.replace("[[page]]", page); const max_commands = iteration + 10; + if (x) return; const embed = new EmbedBuilder() .setColor(15780145) @@ -51,14 +51,12 @@ module.exports = { if (!command.admin){ if(start < iteration){ }else{ - added_commands++ commands = commands + `${prefix}${command.name} | ${command.description}\n`; iteration++ } start++; } }else if(args[0] === command.name){ - fieldName = "Description"; commands = commands + `${prefix}${command.name}\n` embed.setTitle(command.name.charAt(0).toUpperCase() + command.name.slice(1)) if(command.moreHelp){ @@ -66,6 +64,7 @@ module.exports = { commands = commands + `${element}\n` }); } else { + fieldName = "Description"; commands = commands + `${command.description}`; } break; diff --git a/commands/info/mc.js b/commands/info/mc.js deleted file mode 100644 index dac751b..0000000 --- a/commands/info/mc.js +++ /dev/null @@ -1,103 +0,0 @@ -// Code is taken from https://github.com/stphnduvall/mcstatus/blob/master/src/index.ts -// and converted to pure js. - -const net = require('net') -const { EmbedBuilder } = require('discord.js'); - -module.exports = { - name: 'mc', - description: 'get minecraft server information', - hidden: true, - needsWhitelist: true, - async execute({ message, args }) { - let host = ""; - let port = 25565; - if (args[0]) host = args[0]; - - if (host.includes(":")) { - port = host.replace(/.+(?:\:)/g, ""); - host = host.match(/.+(?:\:)/g, "")[0].replace(":", ""); - } - if(host === "") return message.channel.send("No host provided") - let info = await getMinecraftServerInfo(host, port); - if (info) { - const embed = new EmbedBuilder() - embed.setColor("#ee7939") - embed.setTimestamp() - embed.addFields( - { name: "ping", value: info.ping.toString(), inline: false }, - { name: "Player Count", value: info.playercount.toString(), inline: false }, - { name: "Max Players", value: info.maxPlayers.toString(), inline: false }, - { name: "MOTD", value: info.motd, inline: false }, - ) - - message.channel.send({ embeds: [embed] }); - } else { - message.channel.send("Something went wrong\nThe minecraft server is likely not reachable from the discord bot") - } - - } -}; - - - -async function getMinecraftServerInfo(host, port = 25565) { - let serverInfo = { - ping: undefined, - maxPlayers: undefined, - version: undefined, - playercount: undefined, - motd: undefined - } - - let startTime = new Date(); - let data; - let ping; - serverInfo = await new Promise((resolve) => { - const client = net.connect({ host, port }, () => { - ping = Math.round(new Date().getMilliseconds() - startTime.getMilliseconds()); - - let buff = Buffer.from([0xFE, 0x01]); - client.write(buff); - - }) - let error = false; - client.on('data', (d) => { - data = d.toString() - client.destroy(); - - }) - client.once('error', (error) => { - console.error(error) - error = true; - }) - client.once('connectionAttemptFailed', (ip) => { - console.error("in attempt failed") - error = true; - }) - - client.once('connectionAttemptTimeout', (ip) => { - console.error("in attempt timeout") - error = true; - }) - client.on('close', () => { - if (!error) { - let _serverInfo = data?.split('\x00\x00\x00'); - - if (!_serverInfo) { - console.log("Something went wrong.") - resolve(serverInfo) - } - serverInfo.version = _serverInfo[2].replace(/\u0000/g, '') - serverInfo.motd = _serverInfo[3].replace(/\u0000/g, '') - serverInfo.playercount = Number(_serverInfo[4].replace(/\u0000/g, '')) - serverInfo.maxPlayers = Number(_serverInfo[5].replace(/\u0000/g, '')) - serverInfo.ping = Number(ping) - resolve(serverInfo) - } else { - resolve(0) - } - }) - }) - return serverInfo -} diff --git a/commands/info/pfp.js b/commands/info/pfp.js index dd76507..68a4640 100644 --- a/commands/info/pfp.js +++ b/commands/info/pfp.js @@ -16,9 +16,9 @@ module.exports = { let user = message.guild.members.cache.get(info); let guildPfp = user.avatarURL({format: 'png', dynamic: true, size: 4096}); let globalPfp = user.user.avatarURL({format: 'png', dynamic: true, size: 4096}); - let sendText = `${globalPfp}`; + let sendText = `Global pfp:\n${globalPfp}`; if(guildPfp != null){ - sendText = `Global pfp${sendText}\nGuild pfp:\n${guildPfp}`; + sendText = `${sendText}\nGuild pfp:\n${guildPfp}`; } message.channel.send(sendText) diff --git a/commands/info/serverinfo.js b/commands/info/serverinfo.js index 1f329de..1526c32 100644 --- a/commands/info/serverinfo.js +++ b/commands/info/serverinfo.js @@ -15,7 +15,6 @@ module.exports = { {name: "Server Name", value: message.guild.name, inline: false}, {name: "Created", value: convertDateToISOString(message.guild.createdAt), inline: false}, {name: "Members", value: message.guild.memberCount.toString(), inline: false}, - {name: "Channels", value: message.guild.channels.channelCountWithoutThreads.toString(), inline: false}, ]) diff --git a/commands/misc/custom.js b/commands/misc/custom.js index f684b3b..71885df 100644 --- a/commands/misc/custom.js +++ b/commands/misc/custom.js @@ -17,13 +17,10 @@ module.exports = { "custom remove - Delete your custom commands.", "custom owner - check owner of custom command", "custom list - list all custom commands", - "custom variables - list all variables you can use" + "custom variables - list all variables you can use", + "custom count - display the amount of custom commands" ], - execute({message, args, client, prefix, owners}) { - const customPath = 'data/customCommands.json'; - if(!fs.existsSync(customPath)){ - fs.writeFileSync(customPath,"[]") - } + async execute({message, args, client, prefix, owners}) { let sendText; let isEmbed = false; if (args){ @@ -31,19 +28,21 @@ module.exports = { let customMessage = args.slice(2, args.length).join(" "); switch (args[0].toLowerCase()) { - case "add": + case "add":{ if(!customMessage) { message.channel.send("Message can't be empty"); return; } - sendText = addCustomCommand(customName, customMessage, message.author.id); + sendText = await addCustomCommand(client, customName, customMessage, message.author.id); break; + } case "remove": - case "delete": + case "delete":{ sendText = deleteCustomCommand(customName, message.author.id, owners); break; - case "owner": - let author = getOwnerOfCustomCommand(customName); + } + case "owner":{ + let author = await getOwnerOfCustomCommand(customName); let user; if(!author) sendText = `${customName} does not exist` @@ -55,10 +54,11 @@ module.exports = { } break; - case "list": + } + case "list": { const embed = new EmbedBuilder(); - sendText = getAllCustomCommands(); - if(sendText != ""){ + sendText = getAllCustomCommands(client); + if(sendText !== ""){ embed.setColor(15780145) embed.addFields( { name: "Custom commands", value: sendText }, @@ -67,13 +67,16 @@ module.exports = { isEmbed = true; }else sendText = "NO CUSTOM COMMANDS" break; - case "variables": + } + case "variables": { sendText = "The variables you can use are:\n\n\n\n\n\n\n" break; - case "edit": + } + case "edit": { sendText = editCustomCommand(customName, message.author.id, customMessage) break; - case "show": + } + case "show": { let json = fs.readFileSync(customPath, 'utf8'); let customCommands = JSON.parse(json) sendText = "Command not found." @@ -83,12 +86,22 @@ module.exports = { } }); break; - case "rename": + } + case "rename": { sendText = renameCustomCommand(customName, args[2], message.author.id); break; - default: + } + case "count": { + const customPath = './data/customCommands.json'; + let json = fs.readFileSync(customPath, 'utf8'); + let customCommands = JSON.parse(json) + sendText = `There are ${customCommands.length} custom commands in total`; + break; + } + default: { sendText = `Argument not recognized.\n"${prefix}help custom" to see all arguments you can use.` break; + } } } if(isEmbed) message.channel.send({embeds :[sendText]}) diff --git a/commands/misc/dl.js b/commands/misc/dl.js deleted file mode 100644 index 13d95df..0000000 --- a/commands/misc/dl.js +++ /dev/null @@ -1,71 +0,0 @@ -const path = require('path'); -const fs = require('fs') - -const executeCommand = require('../../util/executeCommand'); -module.exports = { - name: 'dl', - description: 'Download a video', - moreHelp: [ - "Usage: dl " - ], - async execute({message, args}) { - const downloadsDir = path.resolve(process.cwd(), 'data', 'downloads', Date.now().toString()); - const cookieFilepath = path.resolve(process.cwd(), 'data', 'cookies.txt') - if(!fs.existsSync(cookieFilepath)) { - message.channel.send("Some dependencies are needed for the command to work properly. Please let the bot's owner know.") - return; - } - fs.mkdirSync(downloadsDir, {recursive: true}); - - let url; - - if(args.length > 0){ - if(args[0].charAt(0) === '<' && args[0].charAt(args[0].length - 1) === '>'){ - args[0] = args[0].slice(1, args[0].length - 1) - } - try { - url = new URL(args[0]); - url = url.href; - } catch (error) { - this.cleanUp(downloadsDir); - message.channel.send("Could not parse the provided argument as a URL."); - return; - } - } else { - this.cleanUp(downloadsDir); - return message.channel.send("You have to provide a URL in an argument.") - } - - const originalMessage = await message.channel.send("Downloading video...") - - if(executeCommand("yt-dlp", [url, "-P", downloadsDir, "--cookies", cookieFilepath]).error){ - originalMessage.edit("An error occurred when downloading the video."); - this.cleanUp(downloadsDir); - return; - } - - - let files = fs.readdirSync(downloadsDir); - if(files.length < 1) { - this.cleanUp(downloadsDir); - originalMessage.edit("Something went wrong when downloading the video.") - return; - } - const filename = files[0]; - - await originalMessage.edit({ - content: null, - files: [{ - attachment: path.resolve(downloadsDir, filename) - }]}) - - this.cleanUp(downloadsDir); - - - }, - - cleanUp(downloadsDir){ - fs.rmSync(downloadsDir, {force: true, recursive: true}); - }, - -} diff --git a/commands/misc/emoji.js b/commands/misc/emoji.js index 6ce12dc..58befa8 100644 --- a/commands/misc/emoji.js +++ b/commands/misc/emoji.js @@ -19,7 +19,8 @@ module.exports = { try { num = num.slice(0, -1); } catch (e) { - message.channel.send("There was an error."); + console.error(e) + message.channel.send("There was an error. Check the logs"); return; } message.channel.send("https://cdn.discordapp.com/emojis/" + num + extension); diff --git a/commands/misc/fm.js b/commands/misc/fm.js index e259f4c..615630c 100644 --- a/commands/misc/fm.js +++ b/commands/misc/fm.js @@ -4,12 +4,6 @@ const getCurrentCover = require("../../util/lastfm/getCurrentCover"); const getTopTracks = require("../../util/lastfm/getTopTracks"); const help = require("../info/help"); const parseMention = require("../../util/parseMention"); -const roast = require("../../util/lastfm/roast"); -const getTopArtists = require("../../util/lastfm/getTopArtists"); -const getTopAlbums = require("../../util/lastfm/getTopAlbums"); -const {EmbedBuilder} = require('discord.js'); -const getNickname = require('../../util/getNickname'); -const isWhitelisted = require("../../util/isWhitelisted"); module.exports = { name: 'fm', description: 'Last fm commands. See `help fm` for more info.', @@ -17,11 +11,8 @@ module.exports = { "They behave the same (for example: `fmtt` and `fm tt`)", "Set username: `fmset `", "Get current scrobble: `fm`", - "Get top artists `fmas`", - "Get top albums: `fmabl`", "Get top tracks: `fmtt`", "Get album cover for current scrobble: `fmcover`", - "Get a roast from an LLM using your top artists and albums: `fmroast`" ], async execute({ message, args, prefix, client }) { let sendText = {text: "Something went wrong.", embed: null}; @@ -37,46 +28,9 @@ module.exports = { args.shift(); sendText = await getTopTracks(message.author.id, args, message.guild); break; - case "topalbums": - case "topalbum": - case "abl": - args.shift(); - sendText = await getTopAlbums(message.author.id, args, message.guild) - break; - case "topartists": - case "topartist": - case "ta": - case "as": - args.shift(); - sendText = await getTopArtists(message.author.id, args, message.guild); - break; case "cover": sendText = await getCurrentCover(message.author.id, message.guild); break; - case "roast": - const commandName = "fmroast" - if(!isWhitelisted.isWhitelisted(commandName, client.whitelist, message.guild.id, message.author.id, isWhitelisted.whitelistTypes.EITHER)) { - message.channel.send("fmroast has not been whitelisted for you or this server.") - return; - } - let topArtists = await getTopArtists(message.author.id, ["yearly"], message.guild, true); - let topAlbums = await getTopAlbums(message.author.id, ["yearly"], message.guild, true); - message.channel.sendTyping(); - let result = await roast(topArtists, topAlbums); - - let parse = parseMention(message.author.id, message.guild) - let user = message.guild.members.cache.get(parse); - let nickname = getNickname(user, message.guild) - if (nickname == null) { - nickname = user.user.username; - } - const possesive = nickname.at(nickname.length - 1) === "s" ? "'" : "'s" - const embed = new EmbedBuilder() - .setAuthor({name: `${nickname}${possesive} AI roast`, iconURL: user.user.avatarURL({ dynamic: true, size: 4096 })}) - .setColor(15780145) - .setDescription(result); - sendText.embed = embed; - break; default: sendText.text = `${args[0]} is not a valid subcommand.\nSee \`${prefix}help fm\` for more info.`; break; @@ -87,16 +41,14 @@ module.exports = { if(sendText.embed != null){ let parse = parseMention(message.author.id, message.guild) let user = message.guild.members.cache.get(parse); - if(!sendText.embed.data.color){ - let roleColor = 15788778; - if (user.roles.color) { - roleColor = user.roles.color.color; - } - sendText.embed.setColor(roleColor); + let roleColor = 15788778; + if (user.roles.color) { + roleColor = user.roles.color.color; } + sendText.embed.setColor(roleColor); message.channel.send({embeds :[sendText.embed]}) }else{ message.channel.send(sendText.text.replaceAll("", prefix)); } } -}; \ No newline at end of file +}; \ No newline at end of file diff --git a/commands/misc/ig.js b/commands/misc/ig.js deleted file mode 100644 index 21268b7..0000000 --- a/commands/misc/ig.js +++ /dev/null @@ -1,28 +0,0 @@ - -module.exports = { - name: 'ig', - description: 'Replaces Instagram links with kkinstagram and deletes the original message', - execute({message, args}) { - const noUrlErr = "You need to provide an Instagram link to use this command." - if(args.length < 1) { - message.channel.send(noUrlErr); - return; - } - let replacedLink = ""; - const regex = /(?<=\/)(instagram)\.com/g - if(args[0].startsWith("https://") || args[0].startsWith("http://")){ - replacedLink = args[0].replace(regex, "kkinstagram.com"); - } - if(replacedLink.length === 0 || args[0] === replacedLink){ - message.channel.send(noUrlErr); - return; - } - message.channel.send(replacedLink); - try{ - message.delete() - }catch(err){ - console.error(`${this.name}: An error occurred while trying to delete the original message.`) - console.error(err); - } - } -}; \ No newline at end of file diff --git a/commands/misc/ping.js b/commands/misc/ping.js index fe9fb09..6e23a0c 100644 --- a/commands/misc/ping.js +++ b/commands/misc/ping.js @@ -1,11 +1,7 @@ module.exports = { name: 'ping', description: 'Just ping.', - async execute({message, client}) { - let apiLatency = client.ws.ping; - const time = process.hrtime.bigint(); - let initialMessage = await message.channel.send(`Pong.`) - const diff = Number(process.hrtime.bigint() - time) * 1e-6; - initialMessage.edit(`Pong.\nAPI latency: ${apiLatency} ms\nMessage latency: ${diff.toFixed(0)} ms.`); + execute({message, client}) { + message.channel.send(`Pong.\n${client.ws.ping}ms`) } }; \ No newline at end of file diff --git a/commands/misc/prefix.js b/commands/misc/prefix.js index 954c834..19ec7d1 100644 --- a/commands/misc/prefix.js +++ b/commands/misc/prefix.js @@ -1,11 +1,10 @@ const setServerPrefix = require("../../util/setServerPrefix"); -const { PermissionsBitField } = require('discord.js'); module.exports = { name: 'prefix', description: 'Change the prefix of the bot in this server.', execute({ message, client, args, prefix }) { - if (!message.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) { + if (!message.member.permissions.has('MANAGE_GUILD')) { message.channel.send("You do not have sufficient permissions(MANAGE_GUILD) to change the prefix of this server.") return; } diff --git a/commands/misc/say.js b/commands/misc/say.js index 2995f6a..e8ca4e6 100644 --- a/commands/misc/say.js +++ b/commands/misc/say.js @@ -1,7 +1,6 @@ module.exports = { name: 'say', description: 'Repeats arguments', - admin: true, execute({message, args}) { if(args.length == 0) diff --git a/commands/misc/tdoss.js b/commands/misc/tdoss.js deleted file mode 100644 index f5430fe..0000000 --- a/commands/misc/tdoss.js +++ /dev/null @@ -1,100 +0,0 @@ -const { execSync } = require('child_process'); -const fs = require('fs'); -const path = require('path'); -const { writeFile } = require('node:fs/promises') -const { Readable } = require('node:stream') -const executeCommand = require('../../util/executeCommand'); - -module.exports = { - name: 'tdoss', - description: 'Combine picture with tdoss album cover template', - async execute({ message, args }) { - - let tdossDir = path.resolve(process.cwd(), 'data', 'tdoss'); - const tdossTemplate = path.resolve(process.cwd(), 'resources', 'tdoss_template.png'); - - const directory = path.resolve(tdossDir, Math.floor(new Date).toString()) - fs.mkdirSync(directory, {recursive: true}) - - let url = ""; - if(message.attachments.size > 0){ - url = message.attachments.first().url - - - } else if(args[0] && args[0].startsWith("https://") ){ - url = args[0]; - }else if(message.reference){ - let referencedMessage = await message.fetchReference(); - if(referencedMessage.attachments.size > 0){ - url = await referencedMessage.attachments.first().url; - } - else { - message.channel.send("The message you replied to doesn't have any attachments."); - return; - } - } - else { - let lastMessages = await message.channel.messages.fetch({limit: 20, cache: false}); - let lastMessageWithAttachment = lastMessages.find(m => m.attachments.size > 0); - if(!lastMessageWithAttachment){ - message.channel.send("Couldn't find an image to use this command on.") - fs.rmSync(`${directory}`, {recursive: true}) - return - } - url = lastMessageWithAttachment.attachments.first().url; - - } - // TODO: Download with correct extension. - message.channel.sendTyping(); - let downloadResult = await this.downloadImage(url, path.resolve(directory, "input.png")); - if(downloadResult.value != this.ERROR_CODES.SUCCESS){ - if(downloadResult.value === this.ERROR_CODES.FETCH_ERROR){ - message.channel.send(`Failed to download the provided image, got error '${downloadResult.errorMessage}'`); - }else if (downloadResult.value === this.ERROR_CODES.HTTP_ERROR){ - message.channel.send(`Failed to download the provided image, got response status '${downloadResult.errorMessage}'`); - }else if(downloadResult.value === this.ERROR_CODES.NOT_IMAGE){ - message.channel.send(`The provided url was not an image.`) - } - fs.rmSync(`${directory}`, {recursive: true}) - return; - } - - - const commandArgs = [tdossTemplate, "(", `${directory}/input.png`, "-resize", "800x800^", "-gravity", "center", "-extent", "1000x1000", ")", "-compose", "dst-over", "-composite", `${directory}/tdoss_result.png`] - if (executeCommand("magick", commandArgs).error === true) { - message.channel.send("Something went wrong during image manipulation.\nTry again and if it keeps happening, contact the owner of the bot.") - fs.rmSync(`${directory}`, {recursive: true}) - return - } - - let final_image = { - attachment: path.resolve(`${directory}/tdoss_result.png`), - name: "tdoss_result.png" - } - - await message.channel.send({files: [final_image]}) - fs.rmSync(`${directory}`, {recursive: true}) - }, - // https://stackoverflow.com/a/77210219 - async downloadImage(url, path) { - let res; - try { - res = await fetch(url); - } catch (error) { - return {value: this.ERROR_CODES.FETCH_ERROR, errorMessage: error.cause?.message || error.message}; - } - if(!res.ok) return {value: this.ERROR_CODES.HTTP_ERROR, errorMessage: res.status.toString()}; - const contentType = res.headers.get('content-type'); - if(!contentType || !contentType.startsWith("image")) return {value: this.ERROR_CODES.NOT_IMAGE, errorMessage: contentType || "No content-type header"}; - const stream = Readable.fromWeb(res.body) - await writeFile(path, stream); - return {value: this.ERROR_CODES.SUCCESS, errorMessage: ""}; - }, - ERROR_CODES: { - SUCCESS: 0, - HTTP_ERROR: 1, - NOT_IMAGE: 2, - FETCH_ERROR: 3 - } - -} diff --git a/commands/misc/timer.js b/commands/misc/timer.js index 522a9aa..cecbebb 100644 --- a/commands/misc/timer.js +++ b/commands/misc/timer.js @@ -4,11 +4,11 @@ const parseTime = require('../../util/timer/parseTime'); const showTimer = require('../../util/timer/showTimer'); module.exports = { name: "timer", - description: "Set a timer for a date or time duration.", + description: "Set a timer for a time in minutes.", moreHelp: ["Usage:" ,"`timer [add|create] `" ,"`timer