commit 74ca98e6dc8735d9349e7f7a766989c5064626b6 Author: kry008 Date: Thu May 23 11:22:31 2024 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f71925a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +config.json +node_modules +package-lock.json \ No newline at end of file diff --git a/commands/argsTest.js b/commands/argsTest.js new file mode 100644 index 0000000..6db0b2a --- /dev/null +++ b/commands/argsTest.js @@ -0,0 +1,121 @@ +module.exports = { + name: 'argumentstest', + description: 'Test command for args', + help: 'This command is used to test the arguments of a command', + arguments: [ + { + name: 'ANY', + type: 'ANY', + description: 'Any type of argument', + required: false, + }, + ], + options: [ + { + name: 'type3', + type: 3, + description: 'STRING', + required: false + }, + { + name: 'type4', + type: 4, + description: 'INTEGER', + required: false + }, + { + name: 'type5', + type: 5, + description: 'BOOLEAN', + required: false + }, + { + name: 'type6', + type: 6, + description: 'USER', + required: false + }, + { + name: 'type7', + type: 7, + description: 'CHANNEL', + required: false + }, + { + name: 'type8', + type: 8, + description: 'ROLE', + required: false + }, + { + name: 'type9', + type: 9, + description: 'MENTIONABLE', + required: false + }, + { + name: 'type10', + type: 10, + description: 'NUMBER', + required: false + }, + { + name: 'type11', + type: 11, + description: 'ATTACHMENT', + required: false + }, + ], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'DM'], + integration_types: [0,1], + execute(message, args) { + message.channel.send('Arguments test command executed'); + var txt = ''; + if(args) { + for (var key in args) { + txt += key + ': ' + args[key] + '\n'; + } + } + message.channel.send(txt); + }, + executeSlash(interaction) { + var stringToReturn = 'Arguments test command executed\n'; + //get which type of argument was passed, and return the value + if(interaction.options.getString('type3')) { + stringToReturn += 'type3: ' + interaction.options.getString('type3') + '\n'; + } + if(interaction.options.getInteger('type4')) { + stringToReturn += 'type4: ' + interaction.options.getInteger('type4') + '\n'; + } + if(interaction.options.getBoolean('type5')) { + stringToReturn += 'type5: ' + interaction.options.getBoolean('type5') + '\n'; + } + if(interaction.options.getUser('type6')) { + stringToReturn += 'type6: ' + interaction.options.getUser('type6').username + '\n'; + } + if(interaction.options.getChannel('type7')) { + stringToReturn += 'type7: ' + interaction.options.getChannel('type7').name + '\n'; + } + if(interaction.options.getRole('type8')) { + stringToReturn += 'type8: ' + interaction.options.getRole('type8').name + '\n'; + } + if(interaction.options.getMentionable('type9')) { + stringToReturn += 'type9: ' + interaction.options.getMentionable('type9').name + '\n'; + } + if(interaction.options.getNumber('type10')) { + stringToReturn += 'type10: ' + interaction.options.getNumber('type10') + '\n'; + } + if(interaction.options.getMessage('type11')) { + stringToReturn += 'type11: ' + interaction.options.getMessage('type11').content + '\n'; + } + + interaction.reply(stringToReturn); + }, +}; diff --git a/commands/ban.js b/commands/ban.js new file mode 100644 index 0000000..0d34e85 --- /dev/null +++ b/commands/ban.js @@ -0,0 +1,65 @@ +module.exports = { + name: 'ban', + description: 'Bans a user from the server', + help: 'This command is used to ban a user from the server. Requires the user to have the "Ban Members" permission. Requires the bot to have the "Ban Members" permission.', + arguments: [ + { + name: 'user', + type: 'USER', + description: 'The user to ban', + required: true, + }, + ], + options: [ + { + name: 'user', + type: 6, + description: 'The user to ban', + required: true, + }, + { + name: 'reason', + type: 3, + description: 'The reason for the ban', + required: false, + }, + ], + slash: true, + text: true, + admin: false, + requireKick: true, + requireBan: false, + canBeUsedInDm: false, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE'], + integration_types: [0], + execute: async (message, args) => { + const user = message.mentions.users.first(); + if (!user) { + return message.reply('You need to mention a user to ban'); + } + const member = message.guild.members.cache.get(user.id); + if (!member) { + return message.reply('That user is not in this server'); + } + if (!member.bannable) { + return message.reply('I cannot ban that user'); + } + const reason = args.slice(1).join(' ') || 'No reason provided'; + await member.ban({ reason }); + message.reply(`${user.tag} has been banned`); + }, + executeSlash: async interaction => { + const user = interaction.options.getUser('user'); + const member = interaction.guild.members.cache.get(user.id); + if (!member) { + return interaction.reply('That user is not in this server'); + } + if (!member.bannable) { + return interaction.reply('I cannot ban that user'); + } + const reason = interaction.options.getString('reason') || 'No reason provided'; + await member.ban({ reason }); + interaction.reply(`${user.tag} has been banned`); + }, +}; \ No newline at end of file diff --git a/commands/cat.js b/commands/cat.js new file mode 100644 index 0000000..aaf750c --- /dev/null +++ b/commands/cat.js @@ -0,0 +1,30 @@ +function returnCat() { + return fetch('https://api.thecatapi.com/v1/images/search') + .then(response => response.json()) + .then(data => data[0].url); +} + +module.exports = { + name: 'cat', + description: 'Get a random cat picture', + help: 'Get a random cat picture', + arguments: [], + options: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + const cat = await returnCat(); + message.channel.send(cat); + }, + executeSlash: async interaction => { + const cat = await returnCat(); + interaction.reply(cat); + }, +}; \ No newline at end of file diff --git a/commands/catFacts.js b/commands/catFacts.js new file mode 100644 index 0000000..dadc30b --- /dev/null +++ b/commands/catFacts.js @@ -0,0 +1,30 @@ +//https://cat-fact.herokuapp.com/facts/random +function returnCatFact() { + return fetch('https://cat-fact.herokuapp.com/facts/random') + .then(response => response.json()) + .then(data => data[0].text); +} +module.exports = { + name: 'catfact', + description: 'Get a random cat fact', + help: 'Get a random cat fact', + arguments: [], + options: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + const catFact = await returnCatFact(); + message.channel.send(catFact); + }, + executeSlash: async interaction => { + const catFact = await returnCatFact(); + interaction.reply(catFact); + }, +}; \ No newline at end of file diff --git a/commands/chuck.js b/commands/chuck.js new file mode 100644 index 0000000..1031032 --- /dev/null +++ b/commands/chuck.js @@ -0,0 +1,30 @@ +//https://api.chucknorris.io/jokes/random +function randomChuck() { + return fetch('https://api.chucknorris.io/jokes/random') + .then(response => response.json()) + .then(data => data.value); +} +module.exports = { + name: 'chuck', + description: 'Get a random Chuck Norris joke', + help: 'Get a random Chuck Norris joke', + arguments: [], + options: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + const chuck = await randomChuck(); + message.channel.send(chuck); + }, + executeSlash: async interaction => { + const chuck = await randomChuck(); + interaction.reply(chuck); + }, +}; \ No newline at end of file diff --git a/commands/colorrgb.js b/commands/colorrgb.js new file mode 100644 index 0000000..9f3b67d --- /dev/null +++ b/commands/colorrgb.js @@ -0,0 +1,143 @@ +// This command converts a RGB color to HEX, HSL, and CMYK +function rgbToHex(r, g, b) { + const red = r.toString(16).padStart(2, '0'); + const green = g.toString(16).padStart(2, '0'); + const blue = b.toString(16).padStart(2, '0'); + return `#${red}${green}${blue}`; +} + +function rgbToHsl(r, g, b) { + const red = r / 255; + const green = g / 255; + const blue = b / 255; + const max = Math.max(red, green, blue); + const min = Math.min(red, green, blue); + const lightness = (max + min) / 2; + if (max === min) { + return { h: 0, s: 0, l: lightness }; + } + const d = max - min; + const saturation = lightness > 0.5 ? d / (2 - max - min) : d / (max + min); + let hue; + switch (max) { + case red: + hue = (green - blue) / d + (green < blue ? 6 : 0); + break; + case green: + hue = (blue - red) / d + 2; + break; + case blue: + hue = (red - green) / d + 4; + break; + } + hue /= 6; + return { h: hue, s: saturation, l: lightness }; +} + +function rgbToCmyk(r, g, b) { + const red = r / 255; + const green = g / 255; + const blue = b / 255; + const black = 1 - Math.max(red, green, blue); + const cyan = (1 - red - black) / (1 - black); + const magenta = (1 - green - black) / (1 - black); + const yellow = (1 - blue - black) / (1 - black); + return { c: cyan, m: magenta, y: yellow, k: black }; +} + +module.exports = { + name: 'colorrgb', + description: 'converts a RGB color to HEX, HSL, and CMYK', + help: 'This command converts a RGB color to HEX, HSL, and CMYK', + arguments: [ + { + name: 'r', + type: 'INTEGER', + description: 'The red value (0-255)', + required: true, + }, + { + name: 'g', + type: 'INTEGER', + description: 'The green value (0-255)', + required: true, + }, + { + name: 'b', + type: 'INTEGER', + description: 'The blue value (0-255)', + required: true, + }, + ], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + options: [ + { + name: 'r', + type: 4, // Integer type + description: 'The red value (0-255)', + required: true + }, + { + name: 'g', + type: 4, // Integer type + description: 'The green value (0-255)', + required: true + }, + { + name: 'b', + type: 4, // Integer type + description: 'The blue value (0-255)', + required: true + } + ], + execute(message, args) { + //check if the user provided the 3 values 0-255 + if (args.length !== 3) { + message.channel.send('You need to provide 3 values (0-255).'); + return; + } + //check if the values are integers + const r = parseInt(args[0]); + const g = parseInt(args[1]); + const b = parseInt(args[2]); + if (isNaN(r) || isNaN(g) || isNaN(b)) { + message.channel.send('The values must be integers.'); + return; + } + //check if the values are between 0 and 255 + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { + message.channel.send('The values must be between 0 and 255.'); + return; + } + //convert the RGB values to HEX + const hex = rgbToHex(r, g, b); + message.channel.send(`HEX: ${hex}`); + const hsl = rgbToHsl(r, g, b); + message.channel.send(`HSL: ${hsl.h.toFixed(2)}, ${hsl.s.toFixed(2)}, ${hsl.l.toFixed(2)}`); + const cmyk = rgbToCmyk(r, g, b); + message.channel.send(`CMYK: ${cmyk.c.toFixed(2)}, ${cmyk.m.toFixed(2)}, ${cmyk.y.toFixed(2)}, ${cmyk.k.toFixed(2)}`); + }, + executeSlash(interaction) { + const r = interaction.options.getInteger('r'); + const g = interaction.options.getInteger('g'); + const b = interaction.options.getInteger('b'); + //check if the values are between 0 and 255 + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { + interaction.reply('The values must be between 0 and 255.'); + return; + } + //convert the RGB values to HEX + const hex = rgbToHex(r, g, b); + const hsl = rgbToHsl(r, g, b); + const cmyk = rgbToCmyk(r, g, b); + interaction.reply(`HEX: ${hex}\nHSL: ${hsl.h.toFixed(2)}, ${hsl.s.toFixed(2)}, ${hsl.l.toFixed(2)}\nCMYK: ${cmyk.c.toFixed(2)}, ${cmyk.m.toFixed(2)}, ${cmyk.y.toFixed(2)}, ${cmyk.k.toFixed(2)}`); + } +}; \ No newline at end of file diff --git a/commands/dns.js b/commands/dns.js new file mode 100644 index 0000000..8c04a00 --- /dev/null +++ b/commands/dns.js @@ -0,0 +1,80 @@ +const dns = require('dns'); + +module.exports = { + name: 'dns', + description: 'Look what is the IP of a domain. Requires a domain as argument.', + help: 'Look what is the IP of a domain. Requires a domain as argument.', + arguments: [ + { + name: 'domain', + type: 'STRING', + description: 'The domain to look up', + required: true, + }, + ], + options: [ + { + name: 'domain', + type: 3, // String type + description: 'The domain to look up', + required: true + } + ], + slash: true, + text: true, + admin: false, + requireKick: false, + premium: false, + requireBan: false, + canBeUsedInDm: true, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute(message, args) { + const domain = args[0]; + if (!domain) { + message.channel.send('You need to provide a domain.'); + return; + } + var ipv4 = ''; + var ipv6 = ''; + dns.lookup(domain, { family: 4 }, (err, addresses) => { + if (err) { + ipv4 = 'Error: not found'; + } else { + ipv4 = 'IP: ' + addresses; + } + dns.lookup(domain, { family: 6 }, (err, addresses) => { + if (err) { + ipv6 = 'Error: not found'; + } else { + ipv6 = 'IP: ' + addresses; + } + message.channel.send('IPv4: ' + ipv4 + '\nIPv6: ' + ipv6); + }); + }) + }, + executeSlash(interaction) { + const domain = interaction.options.getString('domain'); + if (!domain) { + interaction.reply('You need to provide a domain.'); + return; + } + var ipv4 = ''; + var ipv6 = ''; + dns.lookup(domain, { family: 4 }, (err, addresses) => { + if (err) { + ipv4 = 'Error: not found'; + } else { + ipv4 = 'IP: ' + addresses; + } + dns.lookup(domain, { family: 6 }, (err, addresses) => { + if (err) { + ipv6 = 'Error: not found'; + } else { + ipv6 = 'IP: ' + addresses; + } + interaction.reply('IPv4: ' + ipv4 + '\nIPv6: ' + ipv6); + }); + }) + }, +}; diff --git a/commands/dog.js b/commands/dog.js new file mode 100644 index 0000000..a4d590d --- /dev/null +++ b/commands/dog.js @@ -0,0 +1,30 @@ +function returnDog() { + return fetch('https://dog.ceo/api/breeds/image/random') + .then(response => response.json()) + .then(data => data.message); +} + +module.exports = { + name: 'dog', + description: 'Get a random dog picture', + help: 'Get a random dog picture', + arguments: [], + options: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + const dog = await returnDog(); + message.channel.send(dog); + }, + executeSlash: async interaction => { + const dog = await returnDog(); + interaction.reply(dog); + }, +}; \ No newline at end of file diff --git a/commands/fox.js b/commands/fox.js new file mode 100644 index 0000000..81bdccc --- /dev/null +++ b/commands/fox.js @@ -0,0 +1,30 @@ +function returnCat() { + return fetch('https://randomfox.ca/floof/') + .then(response => response.json()) + .then(data => data.image); +} + +module.exports = { + name: 'fox', + description: 'Get a random fox picture', + help: 'Get a random fox picture', + arguments: [], + options: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + const cat = await returnCat(); + message.channel.send(cat); + }, + executeSlash: async interaction => { + const cat = await returnCat(); + interaction.reply(cat); + }, +}; \ No newline at end of file diff --git a/commands/guessNumber.js b/commands/guessNumber.js new file mode 100644 index 0000000..00b78d8 --- /dev/null +++ b/commands/guessNumber.js @@ -0,0 +1,53 @@ +function getRandomIntInclusive(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +module.exports = { + name: 'guessnumber', + description: 'Guess a number between 1 and 100', + help: 'Guess a number between 1 and 100', + arguments: [ + { + name: 'number', + type: 'INTEGER', + description: 'Your guess', + required: true, + }, + ], + options: [ + { + name: 'number', + type: 4, + description: 'Your guess', + required: true, + }, + ], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute(message, args) { + const guess = parseInt(args[0]); + const number = getRandomIntInclusive(1, 100); + if (guess === number) { + message.reply('You guessed the number!'); + } else { + message.reply(`The number was ${number}`); + } + }, + executeSlash(interaction) { + const guess = interaction.options.getInteger('number'); + const number = getRandomIntInclusive(1, 100); + if (guess === number) { + interaction.reply('You guessed the number!'); + } else { + interaction.reply(`The number was ${number}`); + } + }, +}; diff --git a/commands/help.js b/commands/help.js new file mode 100644 index 0000000..58403b8 --- /dev/null +++ b/commands/help.js @@ -0,0 +1 @@ +//optiona name of the command \ No newline at end of file diff --git a/commands/kick.js b/commands/kick.js new file mode 100644 index 0000000..c89cc1d --- /dev/null +++ b/commands/kick.js @@ -0,0 +1,71 @@ +module.exports = { + name: 'kick', + description: 'Kicks a user from the server', + help: 'Kicks a user from the server with a reason if provided. Requires the user to have the "Kick Members" permission. Requires the bot to have the "Kick Members" permission.', + arguments: [ + { + name: 'user', + type: 'USER', + description: 'The user to kick', + required: true, + }, + { + name: 'reason', + type: 'STRING', + description: 'The reason for the kick', + required: false, + }, + ], + options: [ + { + name: 'user', + type: 6, + description: 'The user to kick', + required: true, + }, + { + name: 'reason', + type: 3, + description: 'The reason for the kick', + required: false, + }, + ], + slash: true, + text: true, + admin: false, + requireKick: true, + requireBan: false, + canBeUsedInDm: false, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE'], + integration_types: [0], + execute: async (message, args) => { + const user = message.mentions.users.first(); + if (!user) { + return message.reply('You need to mention a user to kick'); + } + const member = message.guild.members.cache.get(user.id); + if (!member) { + return message.reply('That user is not in this server'); + } + if (!member.kickable) { + return message.reply('I cannot kick that user'); + } + const reason = args.slice(1).join(' ') || 'No reason provided'; + await member.kick(reason); + message.reply(`${user.tag} has been kicked`); + }, + executeSlash: async interaction => { + const user = interaction.options.getUser('user'); + const member = interaction.guild.members.cache.get(user.id); + if (!member) { + return interaction.reply('That user is not in this server'); + } + if (!member.kickable) { + return interaction.reply('I cannot kick that user'); + } + const reason = interaction.options.getString('reason') || 'No reason provided'; + await member.kick(reason); + interaction.reply(`${user.tag} has been kicked`); + }, +}; \ No newline at end of file diff --git a/commands/ping.js b/commands/ping.js new file mode 100644 index 0000000..18d05c5 --- /dev/null +++ b/commands/ping.js @@ -0,0 +1,21 @@ +module.exports = { + name: 'ping', + description: 'Ping!', + help: 'Ping!', + arguments: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + premium: false, + canBeUsedInDm: true, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute(message, args) { + message.channel.send('Pong!'); + }, + executeSlash(interaction) { + interaction.reply('Pong.'); + }, +}; diff --git a/commands/pokemon.js b/commands/pokemon.js new file mode 100644 index 0000000..a9134e8 --- /dev/null +++ b/commands/pokemon.js @@ -0,0 +1,145 @@ +const fs = require('fs'); +//read files databases/pokemon_games.json and databases/pokemon.json +const pokemon_games = JSON.parse(fs.readFileSync('databases/pokemon_games.json')); +const pokemon = JSON.parse(fs.readFileSync('databases/pokemon.json')); + +/*pokemon.json +[ + { + "number": 1, + "name": "Bulbasaur", + "img": "https://en.wikipedia.org/wiki/Bulbasaur#/media/File:Pok%C3%A9mon_Bulbasaur_art.png", + "type": [ + "Grass", + "Poison" + ], + "height": "0.7 m", + "weight": "6.9 kg", + "first_appeared": 1, + "some_facts": [ + "Bulbasaur is the first Pokémon in the National Pokédex.", + "Bulbasaur is the only dual-type Pokémon in the National Pokédex that is both Poison and Grass type.", + "Bulbasaur is the only Pokémon that can learn Frenzy Plant, Blast Burn, and Hydro Cannon." + ] + }, +pokemon_games.json +[ + { + "id": 1, + "name": "Pokémon Red and Blue", + "year": 1996 + } + + */ + + +function randomPokemon() { + //connect data from pokemon.json and pokemon_games.json + const randomPokemon = pokemon[Math.floor(Math.random() * pokemon.length)]; + //find game id in pokemon_games.json + const game = pokemon_games.find(game => game.id === randomPokemon.first_appeared); + //get numbers of facts and get random fact + const fact = randomPokemon.some_facts[Math.floor(Math.random() * randomPokemon.some_facts.length)]; + //get types of pokemon + const types = randomPokemon.type.join(', '); + return `**${randomPokemon.name}**\nTypes: ${types}\nHeight: ${randomPokemon.height}\nWeight: ${randomPokemon.weight}\nFirst appeared in: ${game.name} (${game.year})\n${fact}\n${randomPokemon.img}`; +} + +function pokemonNumber(number) { + const pokemonNumber = pokemon.find(pokemon => pokemon.number === number); + if (!pokemonNumber) { + return 'Pokemon not found **FUNCTION NOT FINISHED**'; + } + const game = pokemon_games.find(game => game.id === pokemonNumber.first_appeared); + const fact = pokemonNumber.some_facts[Math.floor(Math.random() * pokemonNumber.some_facts.length)]; + const types = pokemonNumber.type.join(', '); + return `**${pokemonNumber.name}**\nTypes: ${types}\nHeight: ${pokemonNumber.height}\nWeight: ${pokemonNumber.weight}\nFirst appeared in: ${game.name} (${game.year})\n${fact}`; +} + +function pokemonName(name) { + const pokemonName = pokemon.find(pokemon => pokemon.name.toLowerCase() === name.toLowerCase()); + if (!pokemonName) { + return 'Pokemon not found **FUNCTION NOT FINISHED**'; + } + const game = pokemon_games.find(game => game.id === pokemonName.first_appeared); + const fact = pokemonName.some_facts[Math.floor(Math.random() * pokemonName.some_facts.length)]; + const types = pokemonName.type.join(', '); + return `**${pokemonName.name}**\nTypes: ${types}\nHeight: ${pokemonName.height}\nWeight: ${pokemonName.weight}\nFirst appeared in: ${game.name} (${game.year})\n${fact}`; +} + +module.exports = { + name: 'pokemon', + description: 'Get a random pokemon. **FUNCTION NOT FINISHED**', + help: 'Get a random pokemon. **FUNCTION NOT FINISHED**', + arguments: [ + { + name: 'pokemonname', + type: 'STRING', + description: 'Name of the pokemon you want to get information about', + required: false, + }, + { + name: 'pokemonnumber', + type: 'INTEGER', + description: 'Number of the pokemon you want to get information about', + required: false, + }, + ], + options: [ + { + name: 'pokemonname', + type: 3, // String type + description: 'Name of the pokemon you want to get information about', + required: false + }, + { + name: 'pokemonnumber', + type: 4, // Integer type + description: 'Number of the pokemon you want to get information about', + required: false + } + ], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + premium: false, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + if(args.length === 0) { + const pokemon = randomPokemon(); + message.channel.send(pokemon); + return; + } + //check if it is a number + if(!isNaN(args[0])) { + const pokemon = pokemonNumber(parseInt(args[0])); + message.channel.send(pokemon); + return; + } + //check if it is a string + const pokemon = pokemonName(args.join(' ')); + return message.channel.send(pokemon); + + + }, + executeSlash: async interaction => { + const name = interaction.options.getString('pokemonname'); + const number = interaction.options.getInteger('pokemonnumber'); + if (!name && !number) { + const pokemon = randomPokemon(); + interaction.reply(pokemon); + return; + } + if (number) { + const pokemon = pokemonNumber(number); + interaction.reply(pokemon); + return; + } + const pokemon = pokemonName(name); + interaction.reply(pokemon); + }, +}; \ No newline at end of file diff --git a/commands/profilePicture.js b/commands/profilePicture.js new file mode 100644 index 0000000..556c0e7 --- /dev/null +++ b/commands/profilePicture.js @@ -0,0 +1,38 @@ +module.exports = { + name: 'profilepicture', + description: 'Get the profile picture of a user.', + help: 'Get the profile picture of a user.', + arguments: [ + { + name: 'user', + type: 'User', + description: 'The user to get the profile picture', + required: false + } + ], + options: [ + { + name: 'user', + type: 6, // User type + description: 'The user to get the profile picture', + required: false + } + ], + slash: true, + text: true, + admin: false, + requireKick: false, + premium: false, + requireBan: false, + canBeUsedInDm: true, + contexts: ['GUILD_TEXT', 'DM'], + integration_types: [0,1], + execute(message, args) { + const user = message.mentions.users.first() || message.author; + message.channel.send(user.displayAvatarURL({ dynamic: true })); + }, + executeSlash(interaction) { + const user = interaction.options.getUser('user') || interaction.user; + interaction.reply(user.displayAvatarURL({ dynamic: true })); + }, +}; \ No newline at end of file diff --git a/commands/template b/commands/template new file mode 100644 index 0000000..903bf7b --- /dev/null +++ b/commands/template @@ -0,0 +1,28 @@ +module.exports = { + name: '', + description: '', + help: '', + arguments: [ + { + name: '', + description: '', + type: 3, + required: false, + } + ], + options: [], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + canBeUsedInDm: true, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute(message, args) { + message.channel.send(); + }, + executeSlash(interaction) { + interaction.reply(); + }, +}; diff --git a/commands/waifu.js b/commands/waifu.js new file mode 100644 index 0000000..89a1809 --- /dev/null +++ b/commands/waifu.js @@ -0,0 +1,149 @@ +//waifu img +function returnWaifu(type) { + //check if the type is valid + const validTypes = ['waifu', 'neko', 'shinobu', 'megumin', 'bully', 'cuddle', 'cry', 'hug', 'awoo', 'kiss', 'lick', 'pat', 'smug', 'bonk', 'yeet', 'blush', 'smile', 'wave', 'highfive', 'handhold', 'nom', 'bite', 'glomp', 'slap', 'kill', 'kick', 'happy', 'wink', 'poke', 'dance', 'cringe']; + if (!validTypes.includes(type)) { + return 'Invalid type'; + } + return fetch(`https://api.waifu.pics/sfw/${type}`) + .then(response => response.json()) + .then(data => data.url); +} + +module.exports = { + //make choose list + name: 'waifu', + description: 'Get a random waifu picture', + help: 'Get a random waifu picture with the type you want', + arguments: [ + { + name: 'type', + type: 'STRING', + description: 'The type of waifu picture you want', + required: true, + }, + ], + options: [ + { + name: 'type', + description: 'The type of waifu picture you want', + type: 3, + required: true, + choices: [ + { + name: 'waifu', + value: 'waifu', + }, + { + name: 'neko', + value: 'neko', + }, + { + name: 'shinobu', + value: 'shinobu', + }, + { + name: 'megumin', + value: 'megumin', + }, + { + name: 'cuddle', + value: 'cuddle', + }, + { + name: 'cry', + value: 'cry', + }, + { + name: 'hug', + value: 'hug', + }, + { + name: 'awoo', + value: 'awoo', + }, + { + name: 'kiss', + value: 'kiss', + }, + { + name: 'pat', + value: 'pat', + }, + { + name: 'smug', + value: 'smug', + }, + { + name: 'bonk', + value: 'bonk', + }, + { + name: 'blush', + value: 'blush', + }, + { + name: 'smile', + value: 'smile', + }, + { + name: 'wave', + value: 'wave', + }, + { + name: 'highfive', + value: 'highfive', + }, + { + name: 'handhold', + value: 'handhold', + }, + { + name: 'nom', + value: 'nom', + }, + { + name: 'bite', + value: 'bite', + }, + { + name: 'slap', + value: 'slap', + }, + { + name: 'happy', + value: 'happy', + }, + { + name: 'wink', + value: 'wink', + }, + { + name: 'poke', + value: 'poke', + }, + { + name: 'dance', + value: 'dance', + }, + ], + }, + ], + slash: true, + text: true, + admin: false, + requireKick: false, + requireBan: false, + premium: false, + canBeUsedInDm: true, + contexts: ['GUILD_TEXT', 'GUILD_VOICE', 'DM'], + integration_types: [0,1], + execute: async (message, args) => { + const waifu = await returnWaifu(args[0]); + message.channel.send(waifu); + }, + executeSlash: async interaction => { + const waifu = await returnWaifu(interaction.options.getString('type')); + interaction.reply(waifu); + }, +}; \ No newline at end of file diff --git a/commands/who.js b/commands/who.js new file mode 100644 index 0000000..0b7c68e --- /dev/null +++ b/commands/who.js @@ -0,0 +1,38 @@ +module.exports = { + name: 'who', + description: 'Gets data about a user.', + help: 'Gets data about a user.', + arguments: [ + { + name: 'user', + type: 'User', + description: 'The user to get data', + required: false + } + ], + slash: true, + text: true, + admin: false, + requireKick: false, + premium: false, + requireBan: false, + canBeUsedInDm: false, + contexts: ['GUILD_TEXT', 'DM'], + integration_types: [0,1], + options: [ + { + name: 'user', + type: 6, // User type + description: 'The user to get data', + required: false + } + ], + execute(message, args) { + const user = message.mentions.users.first() || message.author; + message.channel.send(`Username: ${user.username}\nID: ${user.id}\nCreated at: ${user.createdAt}\nBot: ${user.bot ? '✅' : '❌'}`); + }, + executeSlash(interaction) { + const user = interaction.options.getUser('user') || interaction.user; + interaction.reply(`Username: ${user.username}\nID: ${user.id}\nCreated at: ${user.createdAt}\nBot: ${user.bot ? '✅' : '❌'}`); + }, +}; \ No newline at end of file diff --git a/databases/pokemon.json b/databases/pokemon.json new file mode 100644 index 0000000..5d67eb0 --- /dev/null +++ b/databases/pokemon.json @@ -0,0 +1,230 @@ +[ + { + "number": 1, + "name": "Bulbasaur", + "type": [ + "Grass", + "Poison" + ], + "height": "0.7 m", + "weight": "6.9 kg", + "first_appeared": 1, + "some_facts": [ + "Bulbasaur is the first Pokémon in the National Pokédex.", + "Bulbasaur is the only dual-type Pokémon in the National Pokédex that is both Poison and Grass type.", + "Bulbasaur is the only Pokémon that can learn Frenzy Plant, Blast Burn, and Hydro Cannon." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png" + }, + { + "number": 2, + "name": "Ivysaur", + "type": [ + "Grass", + "Poison" + ], + "height": "1.0 m", + "weight": "13.0 kg", + "first_appeared": 1, + "some_facts": [ + "Ivysaur is the evolved form of Bulbasaur.", + "Ivysaur is the only Pokémon that can learn Frenzy Plant, Blast Burn, and Hydro Cannon." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/2.png" + }, + { + "number": 3, + "name": "Venusaur", + "type": [ + "Grass", + "Poison" + ], + "height": "2.0 m", + "weight": "100.0 kg", + "first_appeared": 1, + "some_facts": [ + "Venusaur is the evolved form of Ivysaur.", + "Venusaur is the only Pokémon that can learn Frenzy Plant, Blast Burn, and Hydro Cannon." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/3.png" + }, + { + "number": 4, + "name": "Charmander", + "type": [ + "Fire" + ], + "height": "0.6 m", + "weight": "8.5 kg", + "first_appeared": 1, + "some_facts": [ + "Charmander is the first Fire-type Pokémon in the National Pokédex.", + "Charmander is the only Pokémon that can learn Blast Burn." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/4.png" + }, + { + "number": 5, + "name": "Charmeleon", + "type": [ + "Fire" + ], + "height": "1.1 m", + "weight": "19.0 kg", + "first_appeared": 1, + "some_facts": [ + "Charmeleon is the evolved form of Charmander.", + "Charmeleon is the only Pokémon that can learn Blast Burn." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/5.png" + }, + { + "number": 6, + "name": "Charizard", + "type": [ + "Fire", + "Flying" + ], + "height": "1.7 m", + "weight": "90.5 kg", + "first_appeared": 1, + "some_facts": [ + "Charizard is the evolved form of Charmeleon.", + "Charizard is the only Pokémon that can learn Blast Burn." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/6.png" + }, + { + "number": 7, + "name": "Squirtle", + "type": [ + "Water" + ], + "height": "0.5 m", + "weight": "9.0 kg", + "first_appeared": 1, + "some_facts": [ + "Squirtle is the first Water-type Pokémon in the National Pokédex.", + "Squirtle is the only Pokémon that can learn Hydro Cannon." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/7.png" + }, + { + "number": 8, + "name": "Wartortle", + "type": [ + "Water" + ], + "height": "1.0 m", + "weight": "22.5 kg", + "first_appeared": 1, + "some_facts": [ + "Wartortle is the evolved form of Squirtle.", + "Wartortle is the only Pokémon that can learn Hydro Cannon." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/8.png" + }, + { + "number": 9, + "name": "Blastoise", + "type": [ + "Water" + ], + "height": "1.6 m", + "weight": "85.5 kg", + "first_appeared": 1, + "some_facts": [ + "Blastoise is the evolved form of Wartortle.", + "Blastoise is the only Pokémon that can learn Hydro Cannon." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/9.png" + }, + { + "number": 10, + "name": "Caterpie", + "type": [ + "Bug" + ], + "height": "0.3 m", + "weight": "2.9 kg", + "first_appeared": 1, + "some_facts": [ + "Caterpie is the first Bug-type Pokémon in the National Pokédex." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/10.png" + }, + { + "number": 11, + "name": "Metapod", + "type": [ + "Bug" + ], + "height": "0.7 m", + "weight": "9.9 kg", + "first_appeared": 1, + "some_facts": [ + "Metapod is the evolved form of Caterpie." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/11.png" + }, + { + "number": 12, + "name": "Butterfree", + "type": [ + "Bug", + "Flying" + ], + "height": "1.1 m", + "weight": "32.0 kg", + "first_appeared": 1, + "some_facts": [ + "Butterfree is the evolved form of Metapod." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/12.png" + }, + { + "number": 13, + "name": "Weedle", + "type": [ + "Bug", + "Poison" + ], + "height": "0.3 m", + "weight": "3.2 kg", + "first_appeared": 1, + "some_facts": [ + "Weedle is the first Bug-type Pokémon in the National Pokédex that is also Poison type." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/13.png" + }, + { + "number": 14, + "name": "Kakuna", + "type": [ + "Bug", + "Poison" + ], + "height": "0.6 m", + "weight": "10.0 kg", + "first_appeared": 1, + "some_facts": [ + "Kakuna is the evolved form of Weedle." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/14.png" + }, + { + "number": 15, + "name": "Beedrill", + "type": [ + "Bug", + "Poison" + ], + "height": "1.0 m", + "weight": "29.5 kg", + "first_appeared": 1, + "some_facts": [ + "Beedrill is the evolved form of Kakuna." + ], + "img": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/15.png" + } +] \ No newline at end of file diff --git a/databases/pokemon_games.json b/databases/pokemon_games.json new file mode 100644 index 0000000..c05cf85 --- /dev/null +++ b/databases/pokemon_games.json @@ -0,0 +1,17 @@ +[ + { + "id": 1, + "name": "Pokémon Red and Blue", + "year": 1996 + }, + { + "id": 2, + "name": "Pokémon Yellow", + "year": 1998 + }, + { + "id": 3, + "name": "Pokémon Gold and Silver", + "year": 1999 + } +] \ No newline at end of file diff --git a/deploy-commands.js b/deploy-commands.js new file mode 100644 index 0000000..9832474 --- /dev/null +++ b/deploy-commands.js @@ -0,0 +1,48 @@ +const { REST, Routes, Integration } = require('discord.js'); +const { clientId, token } = require('./config.json'); +const fs = require('fs'); +const path = require('path'); + +const commands = []; +const commandsPath = path.join(__dirname, 'commands'); +const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); + +const contextsMapping = { + GUILD_TEXT: 0, + GUILD_VOICE: 1, + DM: 2 +}; + +for (const file of commandFiles) { + const filePath = path.join(commandsPath, file); + const command = require(filePath); + if (command.slash) { + const slashCommand = { + name: command.name, + description: command.description, + options: command.options || [], + default_permission: command.admin ? false : true, + contexts: command.contexts.map(context => contextsMapping[context]) || [0], + integration_types: command.integration_types || [0], + }; + commands.push(slashCommand); + } +} + + +const rest = new REST({ version: '10' }).setToken(token); + +(async () => { + try { + console.log('Started refreshing application (/) commands.'); + + await rest.put( + Routes.applicationCommands(clientId), + { body: commands }, + ); + + console.log('Successfully reloaded application (/) commands.'); + } catch (error) { + console.error(error); + } +})(); diff --git a/events/newGuild.js b/events/newGuild.js new file mode 100644 index 0000000..9ca0ef8 --- /dev/null +++ b/events/newGuild.js @@ -0,0 +1,9 @@ +const { Events } = require('discord.js'); + +module.exports = { + name: Events.GuildCreate, + once: false, + execute(guild) { + console.log(`Joined guild ${guild.name}`); + } +}; \ No newline at end of file diff --git a/events/ready.js b/events/ready.js new file mode 100644 index 0000000..3d5da04 --- /dev/null +++ b/events/ready.js @@ -0,0 +1,10 @@ +const { Events } = require('discord.js'); + +module.exports = { + name: Events.ClientReady, + once: true, + execute(client) { + console.log(`Ready! Logged in as ${client.user.tag}`); + client.user.setActivity('a game', { type: 'PLAYING' }); + }, +}; diff --git a/events/template b/events/template new file mode 100644 index 0000000..aed4b23 --- /dev/null +++ b/events/template @@ -0,0 +1,9 @@ +const { Events } = require('discord.js'); + +module.exports = { + name: Events.NAME, + once: false, + execute(args) { + //TODO + } +}; \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..c545275 --- /dev/null +++ b/index.js @@ -0,0 +1,128 @@ +const { Client, Events, GatewayIntentBits, Collection, PermissionsBitField } = require('discord.js'); +const { token, prefix, wwwport } = require('./config.json'); +const fs = require('fs'); +const path = require('path'); +var http = require('http'); +http.createServer(function (req, res) { + //res.write('Strona domowa: Bot v2.0, link zaproszenia: https://discord.com/oauth2/authorize?client_id=883390927383724112'); + var json = { + "Strona domowa": "Bot v2.0", + "Link zaproszenia": "https://discord.com/oauth2/authorize?client_id=883390927383724112", + "Status": "Working" + }; + res.write(JSON.stringify(json)); + res.end(); + }).listen(wwwport || 8080); + +const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildMessageReactions, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.GuildMessageTyping, + GatewayIntentBits.DirectMessages, + GatewayIntentBits.DirectMessageReactions, + GatewayIntentBits.DirectMessageTyping + ] +}); + +client.commands = new Collection(); + +const commandsPath = path.join(__dirname, 'commands'); +const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + const filePath = path.join(commandsPath, file); + const command = require(filePath); + if (!command.text) continue; + client.commands.set(command.name, command); +} + +const eventsPath = path.join(__dirname, 'events'); +const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js')); + +for (const file of eventFiles) { + const filePath = path.join(eventsPath, file); + const event = require(filePath); + if (event.once) { + client.once(event.name, (...args) => event.execute(...args)); + } else { + client.on(event.name, (...args) => event.execute(...args)); + } +} + +client.on(Events.MessageCreate, message => { + if (!message.content.startsWith(prefix) || message.author.bot) return; + const args = message.content.slice(1).split(/ +/); + const commandName = args.shift().toLowerCase(); + + if (!client.commands.has(commandName)) return; + + const command = client.commands.get(commandName); + + try { + if(command.admin && !message.member.permissions.has(PermissionsBitField.Flags.Administrator)) { + message.reply('You do not have permission to use this command.'); + return; + } + if (!command.canBeUsedInDm && !message.guild) { + message.reply('This command can only be used in a server.'); + return; + } + if (command.requireKick && !message.member.permissions.has(PermissionsBitField.Flags.KickMembers)) { + message.reply('You do not have permission to use this command.'); + return; + } + if (command.requireBan && !message.member.permissions.has(PermissionsBitField.Flags.BanMembers)) { + message.reply('You do not have permission to use this command.'); + return; + } + if (command.text) { + command.execute(message, args); + message.react('✅'); + } + } catch (error) { + console.error(error); + message.reply('There was an error trying to execute that command!'); + //react message with an emoji X + message.react('❌'); + } +}); + +client.on(Events.InteractionCreate, async interaction => { + if (!interaction.isCommand()) return; + + const command = client.commands.get(interaction.commandName); + + if (!command) return; + + try { + if(command.admin && !interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { + await interaction.reply({ content: 'You do not have permission to use this command!', ephemeral: true }); + return; + } + if (!command.canBeUsedInDm && !interaction.guild) { + await interaction.reply({ content: 'This command can only be used in a server!', ephemeral: true }); + return; + } + if (command.requireKick && !interaction.member.permissions.has(PermissionsBitField.Flags.KickMembers)) { + await interaction.reply({ content: 'You do not have permission to use this command!', ephemeral: true }); + return; + } + if (command.requireBan && !interaction.member.permissions.has(PermissionsBitField.Flags.BanMembers)) { + await interaction.reply({ content: 'You do not have permission to use this command!', ephemeral: true }); + return; + } + if (command.slash) { + await command.executeSlash(interaction); + } + } catch (error) { + console.error(error); + await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); + } +}); + +client.login(token); diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..12e8bb7 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,12 @@ +{ + "watch": ["commands", "deploy-commands.js", "index.js"], + "execMap": { + "js": "node" + }, + "events": { + "restart": "node deploy-commands.js" + }, + "ignore": ["node_modules"], + "ext": "js,json" + } + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3deee02 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "discordjs", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node deploy-commands.js && nodemon index.js", + "test": "nodemon index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^14.15.2", + "nodemon": "^3.1.0" + } +}