├── src ├── logs │ └── .gitkeep ├── data │ ├── media │ │ ├── fonts │ │ │ └── GOTHICB.TTF │ │ └── images │ │ │ └── license.jpg │ └── config.json.public ├── website │ ├── public │ │ ├── assets │ │ │ ├── roles.png │ │ │ ├── artwork.png │ │ │ ├── avatar512.jpg │ │ │ ├── favicon.ico │ │ │ ├── favicon.png │ │ │ ├── index │ │ │ │ ├── hug.png │ │ │ │ ├── welcome.png │ │ │ │ └── dashboard.png │ │ │ ├── web-banner.jpg │ │ │ ├── artwork_shadow.png │ │ │ └── discord-icon.png │ │ ├── js │ │ │ └── scrollAnimation.js │ │ └── css │ │ │ └── index.css │ ├── views │ │ ├── imports.ejs │ │ ├── errors │ │ │ └── 404.ejs │ │ ├── secret.ejs │ │ ├── error.ejs │ │ ├── header.ejs │ │ ├── terms-of-service.ejs │ │ ├── footer.ejs │ │ ├── dashboard │ │ │ ├── settings.ejs │ │ │ ├── sidebar.ejs │ │ │ └── dashboard.ejs │ │ └── index.ejs │ └── settings.json.public ├── utils │ └── random.js ├── commands │ ├── meme │ │ ├── adidas.js │ │ └── meme.js │ ├── other │ │ ├── botvote.js │ │ ├── ping.js │ │ ├── randomnumber.js │ │ ├── whois.js │ │ └── botinfo.js │ ├── media │ │ ├── raccoon.js │ │ ├── avatar.js │ │ ├── waifu.js │ │ ├── neko.js │ │ ├── dog.js │ │ ├── fox.js │ │ └── cat.js │ ├── roleplay │ │ ├── pout.js │ │ ├── cry.js │ │ ├── laugh.js │ │ ├── think.js │ │ ├── happy.js │ │ ├── sleep.js │ │ ├── blush.js │ │ ├── baka.js │ │ ├── wink.js │ │ ├── facepalm.js │ │ ├── bored.js │ │ ├── hug.js │ │ ├── pat.js │ │ ├── shrug.js │ │ ├── slap.js │ │ ├── smile.js │ │ ├── stare.js │ │ ├── bite.js │ │ ├── feed.js │ │ ├── kiss.js │ │ ├── wave.js │ │ ├── cuddle.js │ │ ├── dance.js │ │ ├── poke.js │ │ ├── highfive.js │ │ ├── smug.js │ │ ├── tickle.js │ │ └── fuck.js │ ├── memeGeneration │ │ └── magik.js │ ├── help │ │ ├── support.js │ │ └── help.js │ ├── imageGen │ │ └── license.js │ ├── moderation │ │ ├── unban.js │ │ ├── clear.js │ │ ├── kick.js │ │ ├── ban.js │ │ └── serverstats.js │ ├── invites │ │ └── invite.js │ ├── boorus │ │ ├── konachan.js │ │ ├── gelbooru.js │ │ ├── lolibooru.js │ │ ├── safebooru.js │ │ └── rule34.js │ ├── nsfw │ │ ├── hentaineko.js │ │ ├── hentaiblowjob.js │ │ ├── hentaiwaifu.js │ │ └── hentai.js │ ├── welcome │ │ └── welcome.js │ ├── profile │ │ ├── divorce.js │ │ ├── profile.js │ │ └── marry.js │ └── community-management │ │ └── birthday.js ├── events │ ├── ready.js │ ├── guild-delete.js │ ├── interaction-create.js │ ├── guild-member-add.js │ └── birthday-checker.js ├── deploy-commands.js └── index.js ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── node.js.yml ├── darling.js.code-workspace ├── .gitignore ├── LICENSE ├── package.json ├── .eslintrc.json └── README.md /src/logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: eckigerluca 2 | ko_fi: eckigerluca 3 | -------------------------------------------------------------------------------- /src/data/media/fonts/GOTHICB.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/data/media/fonts/GOTHICB.TTF -------------------------------------------------------------------------------- /src/data/media/images/license.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/data/media/images/license.jpg -------------------------------------------------------------------------------- /src/website/public/assets/roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/roles.png -------------------------------------------------------------------------------- /src/website/public/assets/artwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/artwork.png -------------------------------------------------------------------------------- /src/website/public/assets/avatar512.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/avatar512.jpg -------------------------------------------------------------------------------- /src/website/public/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/favicon.ico -------------------------------------------------------------------------------- /src/website/public/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/favicon.png -------------------------------------------------------------------------------- /src/website/public/assets/index/hug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/index/hug.png -------------------------------------------------------------------------------- /src/website/public/assets/web-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/web-banner.jpg -------------------------------------------------------------------------------- /src/website/public/assets/artwork_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/artwork_shadow.png -------------------------------------------------------------------------------- /src/website/public/assets/discord-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/discord-icon.png -------------------------------------------------------------------------------- /src/website/public/assets/index/welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/index/welcome.png -------------------------------------------------------------------------------- /src/website/public/assets/index/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EckigerLuca/Darling/HEAD/src/website/public/assets/index/dashboard.png -------------------------------------------------------------------------------- /darling.js.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "typescript.tsdk": "node_modules\\typescript\\lib" 9 | } 10 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | config.json 4 | test.js.old 5 | .vscode 6 | settings.json 7 | special/ 8 | note.txt 9 | botstart.sh 10 | start.sh 11 | src/logs/* 12 | !src/logs/.gitkeep 13 | -------------------------------------------------------------------------------- /src/utils/random.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | randomInt: function(min, max) { 3 | min = Math.round(min); 4 | max = Math.round(max); 5 | return Math.floor(Math.random() * (max - min + 1)) + min; 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/data/config.json.public: -------------------------------------------------------------------------------- 1 | { 2 | "token": "TOKEN HERE", 3 | "clientId": "ID HERE", 4 | "color": "#D1BABD CHANGE TO WHATEVER COLOR YOU LIKE", 5 | "topGG": false, 6 | "discordBotListToken": "YOUR TOP.GG BOT TOKEN HERE IF YOU HAVE ONE. CHECK README!", 7 | "mongodbUri": "MONGO DB CONNECTION STRING HERE" 8 | } -------------------------------------------------------------------------------- /src/website/views/imports.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/website/settings.json.public: -------------------------------------------------------------------------------- 1 | { 2 | "website": { 3 | "support": "SUPPORT DISCORD SERVER LINK HERE", 4 | "domain": "http://localhost:5991" 5 | }, 6 | "config": { 7 | "port": 5991, 8 | "callback": "http://localhost:5991/callback", 9 | "clientID": "CLIENTID HERE", 10 | "secret": "CLIENT SECRET HERE", 11 | "privacyPolicy": "PRIVACY POLICY HERE", 12 | "legalName": "YOUR LEGAL NAME HERE" 13 | } 14 | } -------------------------------------------------------------------------------- /src/website/public/js/scrollAnimation.js: -------------------------------------------------------------------------------- 1 | const observer = new IntersectionObserver((entries) => { 2 | entries.forEach((entry) => { 3 | if (entry.isIntersecting) { 4 | entry.target.classList.add('show'); 5 | } else { 6 | entry.target.classList.remove('show'); 7 | } 8 | }); 9 | }); 10 | 11 | const hiddenElements = document.querySelectorAll('.hidden'); 12 | hiddenElements.forEach((element) => observer.observe(element)); 13 | -------------------------------------------------------------------------------- /src/commands/meme/adidas.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | 3 | module.exports = { 4 | data: new SlashCommandBuilder() 5 | .setName('adidas') 6 | .setDescription('adidas.mp4') 7 | .setDMPermission(false), 8 | 9 | async execute(interaction) { 10 | const adidas = 'https://cdn.discordapp.com/attachments/743161085246570638/785943266544713738/Adidas.mp4'; 11 | await interaction.reply(`**Adidas.mp4**\n${adidas}`); 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/events/ready.js: -------------------------------------------------------------------------------- 1 | const logger = require('silly-logger'); 2 | const { ActivityType } = require('discord.js'); 3 | 4 | let num = 0; 5 | 6 | module.exports = { 7 | name: 'ready', 8 | once: true, 9 | execute(client) { 10 | logger.success(`Ready! Logged in as ${client.user.tag}`); 11 | require("../website/index.js")(client); 12 | setInterval(async () => { 13 | if (num == 0) { 14 | client.user.setActivity(`${client.guilds.cache.size} servers | /help`, { type: ActivityType.Watching }); 15 | ++num; 16 | } else if (num == 1) { 17 | client.user.setActivity(`darling-bot.xyz`, { type: ActivityType.Watching }); 18 | --num; 19 | } 20 | }, 15000); 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/commands/other/botvote.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('botvote') 8 | .setDescription('vote for the bot!') 9 | .setDMPermission(false), 10 | 11 | async execute(interaction) { 12 | const embed = new EmbedBuilder() 13 | .setTitle('Vote for me!') 14 | .setDescription('[Click](https://top.gg/bot/743150068726628440)') 15 | .setColor(color); 16 | 17 | await interaction.reply({ embeds: [embed] }); 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: EckigerLuca 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Do ... 16 | 2. Do ... 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Software (please complete the following information):** 25 | discord.js version 26 | node.js version 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /src/commands/other/ping.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('ping') 8 | .setDescription("Returns the Bot's ping!") 9 | .setDMPermission(false), 10 | 11 | async execute(interaction) { 12 | const embed = new EmbedBuilder() 13 | .setColor(color) 14 | .setTitle('Pong!') 15 | .setDescription(`That took ${Math.abs(Date.now() - interaction.createdTimestamp)}ms.\n\nAPI Latency is ${Math.round(interaction.client.ws.ping)}ms`); 16 | 17 | await interaction.reply({ embeds: [embed] }); 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/events/guild-delete.js: -------------------------------------------------------------------------------- 1 | const { MongoClient } = require('mongodb'); 2 | const logger = require('silly-logger'); 3 | const { mongodbUri } = require('../data/config.json'); 4 | 5 | const dbClient = new MongoClient(String(mongodbUri)); 6 | 7 | module.exports = { 8 | name: 'guildDelete', 9 | once: false, 10 | async execute(guild) { 11 | const guildId = guild.id; 12 | const filter = { 13 | _id: guildId, 14 | }; 15 | try { 16 | await dbClient.connect(); 17 | const db = dbClient.db("darling"); 18 | const collections = await db.listCollections().toArray(); 19 | collections.forEach(async c => { 20 | const collection = await db.collection(c.name); 21 | await collection.deleteOne(filter); 22 | }); 23 | } 24 | catch (err) { 25 | logger.error(err); 26 | } 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/website/views/errors/404.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 404 - Not Found 8 | 9 | 10 | 11 |
12 |

404 - Not Found

13 | 404 14 |

Sorry, the page you are looking for could not be found.

15 | or return to the Homepage 16 |
17 | 18 | -------------------------------------------------------------------------------- /src/commands/media/raccoon.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('raccoon') 9 | .setDescription('random raccoon') 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | const response = await fetch('https://eckigerluca.com/api/raccoon'); 14 | const data = await response.json(); 15 | 16 | const embed = new EmbedBuilder() 17 | .setTitle('Raccoon!') 18 | .setColor(color) 19 | .setImage(data.image) 20 | .setFooter({ text: 'Thank you Henry for the images >..<' }); 21 | 22 | await interaction.reply({ embeds: [embed] }); 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /src/commands/roleplay/pout.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('pout') 9 | .setDescription("no u") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('pout'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`no u`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/cry.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('cry') 9 | .setDescription("cry like a baby") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('cry'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user} cries`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/laugh.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('laugh') 9 | .setDescription("laugh") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('laugh'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user} thinks it was funny`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/think.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('think') 9 | .setDescription("thonk") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('think'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user} has big brain moment`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/happy.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('happy') 9 | .setDescription("Feelin' happy?") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('happy'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user} is very happy!`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/sleep.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('sleep') 9 | .setDescription("go 2 bed") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('sleep'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user} thought it was smart to do ZzZz`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/blush.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('blush') 9 | .setDescription("learn2read") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('blush'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user} uhm you're a bit red in your face`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/baka.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('baka') 9 | .setDescription("ДЕБИЛ") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('baka'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setTitle('ДЕБИЛ!') 21 | .setDescription(`${interaction.user} went tsundere`) 22 | .setColor(color) 23 | .setImage(img); 24 | 25 | await interaction.reply({ embeds: [embed] }); 26 | 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/deploy-commands.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { REST } = require('@discordjs/rest'); 3 | const { Routes } = require('discord-api-types/v9'); 4 | const { clientId, token } = require('./data/config.json'); 5 | const logger = require('silly-logger'); 6 | 7 | const commands = []; 8 | 9 | const folders = fs.readdirSync('./src/commands'); 10 | 11 | for (const folder of folders) { 12 | const files = fs.readdirSync(`./src/commands/${folder}`); 13 | for (const file of files) { 14 | const command = require(`./commands/${folder}/${file}`); 15 | commands.push(command.data.toJSON()); 16 | } 17 | } 18 | 19 | const rest = new REST({ version: '9' }).setToken(token); 20 | 21 | (async () => { 22 | try { 23 | await rest.put( 24 | Routes.applicationCommands(clientId), 25 | { body: commands }, 26 | ); 27 | logger.success('Successfully registered application commands.'); 28 | } 29 | catch (error) { 30 | logger.error(error); 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /src/commands/roleplay/wink.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('wink') 9 | .setDescription("are you able to read?") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('wink'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | const embed = new EmbedBuilder() 20 | .setDescription(`${interaction.user}, might want to tell us what is happening?`) 21 | .setColor(color) 22 | .setImage(img); 23 | 24 | await interaction.reply({ embeds: [embed] }); 25 | 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/commands/roleplay/facepalm.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('facepalm') 9 | .setDescription("a gif can say more than a thousand words") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('facepalm'); 15 | return response.results[0].url; 16 | } 17 | const img = await fetchImage(); 18 | const embed = new EmbedBuilder() 19 | .setDescription(`${interaction.user} shows how dumb that shit was`) 20 | .setColor(color) 21 | .setImage(img); 22 | 23 | await interaction.reply({ embeds: [embed] }); 24 | 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/commands/roleplay/bored.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('bored') 9 | .setDescription("show the world how bored you are") 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | async function fetchImage() { 14 | const response = await fetchRandom('bored'); 15 | return response.results[0].url; 16 | } 17 | 18 | const img = await fetchImage(); 19 | 20 | const embed = new EmbedBuilder() 21 | .setDescription(`${interaction.user} is bored so do something or they will stab you`) 22 | .setColor(color) 23 | .setImage(img); 24 | 25 | await interaction.reply({ embeds: [embed] }); 26 | 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ "master" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [16.x, 18.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: 'npm' 29 | - run: npm ci 30 | - run: npm run build --if-present 31 | - run: npm test 32 | -------------------------------------------------------------------------------- /src/website/views/secret.ejs: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /src/commands/media/avatar.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('avatar') 8 | .setDescription('returns your or the avatar of someone else') 9 | .addUserOption(option => 10 | option.setName('user') 11 | .setDescription('Tag a user to get their avatar')) 12 | .setDMPermission(false), 13 | 14 | async execute(interaction) { 15 | let user = interaction.options.getUser('user'); 16 | if (user === null) { 17 | user = interaction.user; 18 | } 19 | const avatar = user.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }); 20 | const embed = new EmbedBuilder() 21 | .setColor(color) 22 | .setDescription(`You requested ${user}'s avatar`) 23 | .setImage(avatar); 24 | await interaction.reply({ embeds: [embed] }); 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-present EckigerLuca 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/commands/roleplay/hug.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('hug') 9 | .setDescription("huggies") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('hug'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} hugs ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/pat.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('pat') 9 | .setDescription("pat pat") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('pat'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} pats ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/shrug.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('shrug') 9 | .setDescription(`ツ`) 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('shrug'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} shrugs ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/slap.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('slap') 9 | .setDescription("SCHLAP") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('slap'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} slaps ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/smile.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('smile') 9 | .setDescription("(*^-^*)") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('smile'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} smiles ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/stare.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('stare') 9 | .setDescription("STaLKER!") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('stare'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} stares ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/bite.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('bite') 9 | .setDescription("bite someone :p") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('bite'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} bites ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/feed.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('feed') 9 | .setDescription("pls give me food") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('feed'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} feeds ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/kiss.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('kiss') 9 | .setDescription("now that's lewd") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('kiss'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} kisses ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/wave.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('wave') 9 | .setDescription("EllO!/GudBaYe") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('wave'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} waves ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/cuddle.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('cuddle') 9 | .setDescription("that's lewd") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('cuddle'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} cuddles ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/dance.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('dance') 9 | .setDescription("Keep On Ravin' Baby") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('dance'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} dances ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/poke.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('poke') 9 | .setDescription("poke poke poke poke poke") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('poke'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} pokes ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/highfive.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('highfive') 9 | .setDescription("highfive someone") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('highfive'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} highfives ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/smug.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('smug') 9 | .setDescription("I don't like where this is going") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('smug'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} smugs ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/roleplay/tickle.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('tickle') 9 | .setDescription("tickle tickle tickle tickle") 10 | .addStringOption(option => option.setName('extra').setDescription('learn2read')) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | let extra = interaction.options.getString('extra'); 15 | 16 | async function fetchImage() { 17 | const response = await fetchRandom('tickle'); 18 | return response.results[0].url; 19 | } 20 | 21 | const img = await fetchImage(); 22 | 23 | if (!extra) { 24 | extra = ''; 25 | } 26 | const embed = new EmbedBuilder() 27 | .setDescription(`${interaction.user} tickles ${extra}`) 28 | .setColor(color) 29 | .setImage(img); 30 | 31 | await interaction.reply({ embeds: [embed] }); 32 | 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "darling.js", 3 | "version": "2.2.3", 4 | "description": "", 5 | "main": "src/index.js", 6 | "author": "EckigerLuca", 7 | "license": "MIT", 8 | "dependencies": { 9 | "@napi-rs/canvas": "^0.1.44", 10 | "@top-gg/sdk": "^3.1.3", 11 | "body-parser": "^1.20.2", 12 | "compression": "^1.7.4", 13 | "discord-api-types": "^0.37.55", 14 | "discord.js": "^14.13.0", 15 | "ejs": "^3.1.9", 16 | "events": "^3.3.0", 17 | "express": "^4.18.2", 18 | "express-session": "^1.17.3", 19 | "http": "^0.0.1-security", 20 | "memorystore": "^1.6.7", 21 | "mongodb": "^5.8.0", 22 | "nekos-best.js": "^6.3.0", 23 | "node-fetch": "^2.6.1", 24 | "node-schedule": "^2.1.1", 25 | "passport": "^0.6.0", 26 | "passport-discord": "^0.1.4", 27 | "serve-favicon": "^2.5.0", 28 | "silly-logger": "^1.3.0", 29 | "topgg-autoposter": "^2.0.1" 30 | }, 31 | "scripts": { 32 | "test": "echo \"Do you really need this?\" && exit 0", 33 | "deploy": "node ./src/deploy-commands.js", 34 | "start": "node ./src/index.js", 35 | "dev": "supervisor ./src/index.js" 36 | }, 37 | "devDependencies": { 38 | "eslint": "^8.7.0", 39 | "supervisor": "^0.12.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/commands/memeGeneration/magik.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('magik') 9 | .setDescription('create magik') 10 | .addUserOption(option => option.setName('target').setDescription('user to magik').setRequired(false)) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | await interaction.deferReply(); 15 | let target = interaction.options.getUser('target'); 16 | if (target === null) { 17 | target = interaction.user; 18 | } 19 | const avatar = target.displayAvatarURL({ size: 512, extension: 'jpg', forceStatic: true }); 20 | const response = await fetch(`https://nekobot.xyz/api/imagegen?type=magik&image=${avatar}`); 21 | const data = await response.json(); 22 | 23 | const embed = new EmbedBuilder() 24 | .setTitle('Magik') 25 | .setColor(color) 26 | .setImage(data.message); 27 | await interaction.editReply({ embeds: [embed] }); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/commands/help/support.js: -------------------------------------------------------------------------------- 1 | const { color } = require('../../data/config.json'); 2 | const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); 3 | 4 | module.exports = { 5 | data: new SlashCommandBuilder() 6 | .setName('support') 7 | .setDescription('Get support for Darling') 8 | .setDMPermission(false), 9 | 10 | async execute(interaction) { 11 | const embed = new EmbedBuilder() 12 | .setTitle('Support') 13 | .setDescription("If you need help with Darling, feel free to join the Support Server. We'll be happy to help you!\nMake sure to also check out the Website or the GitHub Repository. Everything is also linked there.") 14 | .setColor(color); 15 | 16 | const row = new ActionRowBuilder() 17 | .addComponents( 18 | new ButtonBuilder() 19 | .setLabel('Support Server') 20 | .setURL('https://discord.gg/tpUr7d3') 21 | .setStyle(ButtonStyle.Link), 22 | new ButtonBuilder() 23 | .setLabel('Website') 24 | .setURL('https://darling-bot.xyz') 25 | .setStyle(ButtonStyle.Link), 26 | new ButtonBuilder() 27 | .setLabel('GitHub') 28 | .setURL('https://github.com/eckigerluca/darling') 29 | .setStyle(ButtonStyle.Link), 30 | ); 31 | 32 | await interaction.reply({ embeds: [embed], components: [row] }); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/commands/imageGen/license.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder, AttachmentBuilder } = require('discord.js'); 2 | const { createCanvas, GlobalFonts, loadImage } = require('@napi-rs/canvas'); 3 | 4 | module.exports = { 5 | data: new SlashCommandBuilder() 6 | .setName('lolilicense') 7 | .setDescription('get a qualified loli license') 8 | .setDMPermission(false), 9 | 10 | async execute(interaction) { 11 | await interaction.deferReply(); 12 | const user = interaction.user.username; 13 | 14 | const canvas = createCanvas(1080, 611); 15 | const context = canvas.getContext('2d'); 16 | GlobalFonts.registerFromPath('src/data/media/fonts/GOTHICB.TTF', 'Century Gothic'); 17 | // Canvas.registerFont('src/data/media/fonts/GOTHICB.TTF', { family: 'Century Gothic' }); 18 | 19 | const lolilicense = await loadImage('src/data/media/images/license.jpg'); 20 | context.drawImage(lolilicense, 0, 0, canvas.width, canvas.height); 21 | 22 | context.font = '20pt "Century Gothic"'; 23 | context.fillStyle = '#000000'; 24 | 25 | context.fillText(user, 450, 128); 26 | 27 | 28 | const attachment = new AttachmentBuilder(await canvas.encode('jpeg'), { name: 'lolilicense.jpg' }); 29 | interaction.editReply({ files: [attachment] }); 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 2021 9 | }, 10 | "rules": { 11 | "comma-dangle": ["error", "always-multiline"], 12 | "comma-spacing": "error", 13 | "comma-style": "error", 14 | "curly": ["error", "multi-line", "consistent"], 15 | "dot-location": ["error", "property"], 16 | "eol-last": "error", 17 | "handle-callback-err": "off", 18 | "keyword-spacing": "error", 19 | "max-nested-callbacks": ["error", { "max": 4 }], 20 | "max-statements-per-line": ["error", { "max": 2 }], 21 | "no-console": "off", 22 | "no-empty-function": "error", 23 | "no-floating-decimal": "error", 24 | "no-inline-comments": "error", 25 | "no-lonely-if": "error", 26 | "no-multi-spaces": "error", 27 | "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], 28 | "no-shadow": ["error", { "allow": ["err", "resolve", "reject"] }], 29 | "no-trailing-spaces": ["error"], 30 | "no-var": "error", 31 | "object-curly-spacing": ["error", "always"], 32 | "prefer-const": "warn", 33 | "semi": ["error", "always"], 34 | "space-before-function-paren": ["error", { 35 | "anonymous": "never", 36 | "named": "never", 37 | "asyncArrow": "always" 38 | }], 39 | "space-in-parens": "error", 40 | "space-infix-ops": "error", 41 | "space-unary-ops": "error", 42 | "spaced-comment": "error", 43 | "yoda": "error", 44 | "no-unused-vars": "warn" 45 | } 46 | } -------------------------------------------------------------------------------- /src/commands/roleplay/fuck.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('fuck') 9 | .setDescription('bang someone really hard') 10 | .addUserOption(option => option.setName('target').setDescription('the person you want to bang').setRequired(true)) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | const user = interaction.options.getUser('target'); 15 | 16 | const sfwGif = 'https://eckigerluca.com/darling/media/fuck/fuck.gif'; 17 | 18 | if (interaction.channel.nsfw) { 19 | const response = await fetch('https://eckigerluca.com/api/fuck'); 20 | const data = await response.json(); 21 | 22 | const embed = new EmbedBuilder() 23 | .setDescription(`${interaction.user} bangs the shit out of ${user}`) 24 | .setColor(color) 25 | .setImage(data.image); 26 | await interaction.reply({ embeds: [embed] }); 27 | } else { 28 | const embed = new EmbedBuilder() 29 | .setDescription(`${interaction.user} is doing lewd things to ${user}`) 30 | .setColor(color) 31 | .setImage(sfwGif); 32 | await interaction.reply({ embeds: [embed] }); 33 | } 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/website/public/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #36393f; 3 | color: white; 4 | } 5 | html { 6 | scroll-behavior: smooth; 7 | } 8 | .slideIn { 9 | -webkit-animation-name: slideIn; 10 | animation-name: slideIn; 11 | } 12 | @media (min-width: 768px) { 13 | .animate { 14 | animation-duration: 0.3s; 15 | -webkit-animation-duration: 0.3s; 16 | animation-fill-mode: both; 17 | -webkit-animation-fill-mode: both; 18 | } 19 | } 20 | 21 | @keyframes slideIn { 22 | 0% { 23 | transform: translateY(-1rem); 24 | opacity: 0; 25 | } 26 | 27 | 100% { 28 | transform: translateY(0rem); 29 | opacity: 1; 30 | } 31 | 32 | 0% { 33 | transform: translateY(-1rem); 34 | opacity: 0; 35 | } 36 | } 37 | 38 | @-webkit-keyframes slideIn { 39 | 0% { 40 | -webkit-transform: transform; 41 | -webkit-opacity: 0; 42 | } 43 | 44 | 100% { 45 | -webkit-transform: translateY(0); 46 | -webkit-opacity: 1; 47 | } 48 | 49 | 0% { 50 | -webkit-transform: translateY(-1rem); 51 | -webkit-opacity: 0; 52 | } 53 | } 54 | #footer-copy { 55 | margin-bottom: -5em; 56 | } 57 | #footer-whole { 58 | clear: both; 59 | bottom: 0; 60 | margin: auto; 61 | width: 100%; 62 | position: relative; 63 | } 64 | #footer-content { 65 | margin-left: 1rem; 66 | margin-right: 1rem; 67 | } 68 | @media (max-width: 767px) { 69 | #footer-whole { 70 | height: auto; 71 | bottom: 0; 72 | width: auto; 73 | } 74 | } -------------------------------------------------------------------------------- /src/commands/other/randomnumber.js: -------------------------------------------------------------------------------- 1 | const { bold, EmbedBuilder, SlashCommandBuilder } = require('discord.js'); 2 | const { color } = require('../../data/config.json'); 3 | const { randomInt } = require('../../utils/random'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('random') 8 | .setDescription('Random stuff') 9 | .addSubcommand(subcommand => 10 | subcommand 11 | .setName('number') 12 | .setDescription('returns a random number') 13 | .addIntegerOption(option => option.setName('start').setDescription('Start of Range')) 14 | .addIntegerOption(option => option.setName('end').setDescription('End of Range'))) 15 | .setDMPermission(false), 16 | 17 | async execute(interaction) { 18 | const startRange = interaction.options.getInteger('start') || 1; 19 | const endRange = interaction.options.getInteger('end') || startRange + 100; 20 | 21 | if (startRange >= endRange) { 22 | interaction.reply({ 23 | content: "Your start can't be greater than or equal to your end silly!", 24 | ephemeral: true, 25 | }); 26 | return; 27 | } 28 | const randomNumber = await randomInt(startRange, endRange); 29 | 30 | const embed = new EmbedBuilder() 31 | .setTitle('Random Number') 32 | .setDescription(`Your random number is: ${bold(randomNumber)}`) 33 | .setColor(color); 34 | await interaction.reply({ embeds: [embed] }); 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /src/commands/moderation/unban.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js'); 2 | 3 | module.exports = { 4 | data: new SlashCommandBuilder() 5 | .setName('unban') 6 | .setDescription('unban a user') 7 | .addStringOption(option => option.setName('userid').setDescription('UserID that you want to unban').setRequired(true)) 8 | .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers) 9 | .setDMPermission(false), 10 | 11 | async execute(interaction) { 12 | if (!interaction.guild.members.me.permissions.has(PermissionFlagsBits.BanMembers)) { 13 | await interaction.reply({ content: "I am missing permission to do that!", ephemeral: true }); 14 | return; 15 | } 16 | 17 | const userID = interaction.options.getString('userid'); 18 | const messageAuthor = await interaction.guild.members.fetch(interaction.member.id); 19 | if (messageAuthor.permissions.has(PermissionFlagsBits.BanMembers)) { 20 | const guild = await interaction.guild.fetch(); 21 | await guild.members.unban(userID).then((user) => { 22 | interaction.reply({ content: `Successfully unbanned ${user.username} from the server!` }); 23 | }).catch(() => { 24 | interaction.reply({ content: "Please define a valid ID, resp. the ID of a banned member!", ephemeral: true }); return; 25 | }); 26 | } 27 | else { 28 | await interaction.reply({ content: "You're not allowed to do that!", ephemeral: true }); return; 29 | } 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /src/commands/invites/invite.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder, PermissionsBitField } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('invite') 8 | .setDescription('Invite links!') 9 | .addSubcommand(subcommand => 10 | subcommand 11 | .setName('bot') 12 | .setDescription('My invite link!')) 13 | .addSubcommand(subcommand => 14 | subcommand 15 | .setName('server') 16 | .setDescription('Server Invite Link')) 17 | .setDMPermission(false), 18 | 19 | async execute(interaction) { 20 | if (interaction.options.getSubcommand() === 'bot') { 21 | const embed = new EmbedBuilder() 22 | .setTitle('Invite link') 23 | .setDescription('[Click me ヽ(✿゚▽゚)ノ](https://eckigerluca.com/darling/invite)') 24 | .setColor(color); 25 | await interaction.reply({ embeds: [embed] }); 26 | return; 27 | } 28 | else if (interaction.options.getSubcommand() === 'server') { 29 | if (interaction.member.permissions.has(PermissionsBitField.Flags.CreateInstantInvite)) { 30 | const invite = interaction.channel.createInvite({ unique: true, maxAge: 300 }); 31 | await interaction.reply({ content: `Here is your link: ${await invite}\nNote: This invite is usable for five minutes!`, ephemeral: true }); 32 | } 33 | else { await interaction.reply({ content: "I'm sorry, but you're not allowed to do that!", ephemeral: true }); } 34 | } 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /src/website/views/error.ejs: -------------------------------------------------------------------------------- 1 | 6 | 7 | <% if (req.query.error) { %> 8 | 9 | 10 | 11 | 12 | 13 | 30 | 31 | 35 | <% } %> -------------------------------------------------------------------------------- /src/commands/media/waifu.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('waifu') 9 | .setDescription('Returns a random waifu pic') 10 | .addStringOption(option => 11 | option.setName('amount') 12 | .setDescription('Defines how many images the bot should send') 13 | .setRequired(true) 14 | .addChoices( 15 | { 16 | name: 'One', 17 | value: '1', 18 | }, 19 | { 20 | name: 'Five', 21 | value: '5', 22 | }, 23 | { 24 | name: 'Ten', 25 | value: '10', 26 | }, 27 | )) 28 | .setDMPermission(false), 29 | 30 | async execute(interaction) { 31 | const amount = parseInt(interaction.options.getString('amount')); 32 | 33 | async function fetchImage() { 34 | const response = await fetch('https://api.waifu.pics/sfw/waifu'); 35 | const data = await response.json(); 36 | const img_url = data.url; 37 | return img_url; 38 | } 39 | 40 | const fetches = Array.from(Array(amount), () => fetchImage()); 41 | const images = await Promise.all(fetches); 42 | const embeds = []; 43 | 44 | images.forEach((img) => { 45 | const embed = new EmbedBuilder() 46 | .setColor(color) 47 | .setTitle('Random waifu pic?') 48 | .setFooter({ text: 'From waifu.pics' }) 49 | .setImage(img); 50 | embeds.push(embed); 51 | }); 52 | 53 | await interaction.reply({ embeds: embeds }); 54 | }, 55 | }; 56 | -------------------------------------------------------------------------------- /src/commands/media/neko.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { fetchRandom } = require ('nekos-best.js'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('neko') 9 | .setDescription('Returns a random neko') 10 | .addStringOption(option => 11 | option.setName('amount') 12 | .setDescription('Defines how many images the bot should send') 13 | .setRequired(true) 14 | .addChoices( 15 | { 16 | name: 'One', 17 | value: '1', 18 | }, 19 | { 20 | name: 'Five', 21 | value: '5', 22 | }, 23 | { 24 | name: 'Ten', 25 | value: '10', 26 | }, 27 | )) 28 | .setDMPermission(false), 29 | 30 | async execute(interaction) { 31 | let amount = interaction.options.getString('amount'); 32 | amount = parseInt(amount); 33 | 34 | async function fetchImage() { 35 | const response = await fetchRandom('neko'); 36 | return response.results[0]; 37 | } 38 | 39 | const fetches = Array.from(Array(amount), () => fetchImage()); 40 | const nekos = await Promise.all(fetches); 41 | const embeds = []; 42 | 43 | nekos.forEach((neko) => { 44 | const embed = new EmbedBuilder() 45 | .setColor(color) 46 | .setTitle('Meow') 47 | .setDescription(`[${neko.artist_name}](${neko.source_url})`) 48 | .setFooter({ text: 'From nekos.best' }) 49 | .setImage(neko.url); 50 | embeds.push(embed); 51 | }); 52 | 53 | await interaction.reply({ embeds: embeds }); 54 | }, 55 | }; 56 | -------------------------------------------------------------------------------- /src/commands/media/dog.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('dog') 9 | .setDescription('Returns a random dog') 10 | .addStringOption(option => 11 | option.setName('amount') 12 | .setDescription('Defines how many images the bot should send') 13 | .setRequired(true) 14 | .addChoices( 15 | { 16 | name: 'One', 17 | value: '1', 18 | }, 19 | { 20 | name: 'Five', 21 | value: '5', 22 | }, 23 | { 24 | name: 'Ten', 25 | value: '10', 26 | }, 27 | )) 28 | .setDMPermission(false), 29 | 30 | async execute(interaction) { 31 | const amount = parseInt(interaction.options.getString('amount')); 32 | 33 | async function fetchImage() { 34 | const response = await fetch('https://random.dog/woof.json'); 35 | const data = await response.json(); 36 | const img_url = data.url; 37 | return img_url; 38 | } 39 | 40 | const fetches = Array.from(Array(amount), () => fetchImage()); 41 | const images = await Promise.all(fetches); 42 | const embeds = []; 43 | 44 | images.forEach((img) => { 45 | const embed = new EmbedBuilder() 46 | .setColor(color) 47 | .setTitle('Woof!') 48 | .setDescription(`[Link if you can't see the image](${img})`) 49 | .setFooter({ text: 'From random.dog' }) 50 | .setImage(img); 51 | embeds.push(embed); 52 | }); 53 | 54 | await interaction.reply({ embeds: embeds }); 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /src/commands/media/fox.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('fox') 9 | .setDescription('Returns a random fox') 10 | .addStringOption(option => 11 | option.setName('amount') 12 | .setDescription('Defines how many images the bot should send') 13 | .setRequired(true) 14 | .addChoices( 15 | { 16 | name: 'One', 17 | value: '1', 18 | }, 19 | { 20 | name: 'Five', 21 | value: '5', 22 | }, 23 | { 24 | name: 'Ten', 25 | value: '10', 26 | }, 27 | )) 28 | .setDMPermission(false), 29 | 30 | async execute(interaction) { 31 | const amount = parseInt(interaction.options.getString('amount')); 32 | 33 | async function fetchImage() { 34 | const response = await fetch('https://randomfox.ca/floof/'); 35 | const data = await response.json(); 36 | const img_url = data.image; 37 | return img_url; 38 | } 39 | 40 | const fetches = Array.from(Array(amount), () => fetchImage()); 41 | const images = await Promise.all(fetches); 42 | const embeds = []; 43 | 44 | images.forEach((img) => { 45 | const embed = new EmbedBuilder() 46 | .setColor(color) 47 | .setTitle('Floof!') 48 | .setDescription(`[Link if you can't see the image](${img})`) 49 | .setFooter({ text: 'From randomfox.ca' }) 50 | .setImage(img); 51 | embeds.push(embed); 52 | }); 53 | 54 | await interaction.reply({ embeds: embeds }); 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /src/commands/media/cat.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('cat') 9 | .setDescription('Returns a random cat') 10 | .addStringOption(option => 11 | option.setName('amount') 12 | .setDescription('Defines how many images the bot should send') 13 | .setRequired(true) 14 | .addChoices( 15 | { 16 | name: 'One', 17 | value: '1', 18 | }, 19 | { 20 | name: 'Five', 21 | value: '5', 22 | }, 23 | { 24 | name: 'Ten', 25 | value: '10', 26 | }, 27 | )) 28 | .setDMPermission(false), 29 | 30 | async execute(interaction) { 31 | const amount = parseInt(interaction.options.getString('amount')); 32 | 33 | async function fetchImage() { 34 | const response = await fetch('https://cataas.com/cat?json=true'); 35 | const data = await response.json(); 36 | const img_url = `https://cataas.com${data.url}`; 37 | return img_url; 38 | } 39 | 40 | const fetches = Array.from(Array(amount), () => fetchImage()); 41 | const images = await Promise.all(fetches); 42 | const embeds = []; 43 | 44 | images.forEach((img) => { 45 | const embed = new EmbedBuilder() 46 | .setColor(color) 47 | .setTitle('Meow!') 48 | .setDescription(`[Link if you can't see the image](${img})`) 49 | .setImage(img) 50 | .setFooter({ text: 'From cataas.com' }); 51 | embeds.push(embed); 52 | }); 53 | 54 | await interaction.reply({ embeds: embeds }); 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /src/commands/boorus/konachan.js: -------------------------------------------------------------------------------- 1 | const { italic, SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('konachan') 9 | .setDescription('search konachan board') 10 | .addStringOption(option => option.setName('tags').setDescription('tags to search for').setRequired(true)) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | if (!interaction.channel.nsfw) { 15 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 16 | return; 17 | } 18 | 19 | await interaction.deferReply(); 20 | const query = interaction.options.getString('tags'); 21 | if (query.split(' ').length > 2) return interaction.editReply({ content: "Max. amount of tags is 2." }); 22 | 23 | const response = await fetch(`https://konachan.com/post.json?limit=99&tags=${query}`); 24 | const data = await response.json(); 25 | const randomInt = Math.floor(Math.random() * (Object.keys(data).length - 0) + 0); 26 | 27 | if (!data.length) { 28 | await interaction.editReply(`I'm so sorry but I can't find anything with the tag(s) ${italic(query)}`); 29 | return; 30 | } 31 | 32 | const imgUrl = data[randomInt].file_url; 33 | const postId = data[randomInt].id; 34 | const postUrl = `https://konachan.com/post/show/${postId}`; 35 | 36 | const embed = new EmbedBuilder() 37 | .setTitle(`Post URL`) 38 | .setURL(postUrl) 39 | .setDescription(`Board: konachan.com\nQueried Tag(s): ${query}\nRequested by: ${interaction.member}`) 40 | .setColor(color) 41 | .setImage(imgUrl) 42 | .setFooter({ text: "This content is served by an image-search api and Darling is not responsible for any content!" }); 43 | 44 | await interaction.editReply({ embeds: [embed] }); 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /src/commands/moderation/clear.js: -------------------------------------------------------------------------------- 1 | const { color } = require('../../data/config.json'); 2 | const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); 3 | 4 | module.exports = { 5 | data: new SlashCommandBuilder() 6 | .setName('clear') 7 | .setDescription('deletes a specified amount of messages in a channel') 8 | .addIntegerOption(option => 9 | option 10 | .setName('amount') 11 | .setDescription('define amount of messages to delete') 12 | .setRequired(true) 13 | .setMinValue(1) 14 | .setMaxValue(100)) 15 | .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) 16 | .setDMPermission(false), 17 | 18 | async execute(interaction) { 19 | await interaction.deferReply({ ephemeral: true }); 20 | if (!interaction.guild.members.me.permissions.has(PermissionFlagsBits.ManageMessages)) { 21 | await interaction.editReply({ content: "I'm sorry, but I'm missing permission to do that!" }); 22 | return; 23 | } 24 | if (!interaction.member.permissions.has(PermissionFlagsBits.ManageMessages)) { 25 | await interaction.editReply({ content: "I'm sorry, but you're not allowed to do that!" }); 26 | return; 27 | } 28 | 29 | const amount = interaction.options.getInteger('amount'); 30 | const messages = await interaction.channel.messages.fetch({ limit: amount }); 31 | if (messages.find(msg => Date.now() - msg.createdAt >= 1000 * 60 * 60 * 24 * 14)) { 32 | await interaction.editReply({ content: "I'm sorry, but I can't delete messages which are older than 14 days!" }); 33 | return; 34 | } 35 | 36 | await interaction.channel.bulkDelete(messages); 37 | const embed = new EmbedBuilder() 38 | .setTitle(`Deleted ${messages.size} messages! 🧹`) 39 | .setColor(color) 40 | .setThumbnail("https://eckigerluca.com/darling/media/cleaning.gif"); 41 | await interaction.editReply({ embeds: [embed] }); 42 | await new Promise(resolve => setTimeout(resolve, 6000)); 43 | }, 44 | }; 45 | -------------------------------------------------------------------------------- /src/commands/boorus/gelbooru.js: -------------------------------------------------------------------------------- 1 | const { italic, SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('gelbooru') 9 | .setDescription('search gelbooru.com board') 10 | .addStringOption(option => option.setName('tags').setDescription('tags to search for').setRequired(true)) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | if (!interaction.channel.nsfw) { 15 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 16 | return; 17 | } 18 | 19 | await interaction.deferReply(); 20 | const query = interaction.options.getString('tags'); 21 | if (query.split(' ').length > 2) return interaction.editReply({ content: "Max. amount of tags is 2." }); 22 | 23 | const response = await fetch(`https://gelbooru.com/index.php?page=dapi&s=post&q=index&json=1&tags=${query}`); 24 | const data = await response.json(); 25 | 26 | if (!data?.post) { 27 | await interaction.editReply(`I'm so sorry but I can't find anything with the tag(s) ${italic(query)}`); 28 | return; 29 | } 30 | 31 | const randomInt = Math.floor(Math.random() * (Object.keys(data.post).length - 0) + 0); 32 | 33 | const postId = data.post[randomInt].id; 34 | 35 | const postUrl = `https://gelbooru.com/index.php?page=post&s=view&id=${postId}`; 36 | const imgUrl = data.post[randomInt].file_url; 37 | 38 | const embed = new EmbedBuilder() 39 | .setTitle(`Post URL`) 40 | .setURL(postUrl) 41 | .setDescription(`Board: gelbooru.com\nQueried Tag(s): ${query}\nRequested by: ${interaction.member}`) 42 | .setColor(color) 43 | .setImage(imgUrl) 44 | .setFooter({ text: "This content is served by an image-search api and Darling is not responsible for any content!" }); 45 | 46 | await interaction.editReply({ embeds: [embed] }); 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /src/commands/boorus/lolibooru.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder, italic } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('lolibooru') 9 | .setDescription('search lolibooru.moe board') 10 | .addStringOption(option => option.setName('tags').setDescription('tags to search for').setRequired(true)) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | if (!interaction.channel.nsfw) { 15 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 16 | return; 17 | } 18 | 19 | await interaction.deferReply(); 20 | const query = interaction.options.getString('tags'); 21 | if (query.split(' ').length > 2) return interaction.editReply({ content: "Max. amount of tags is 2." }); 22 | 23 | const response = await fetch(`https://lolibooru.moe/post/index.json?page=dapi&s=post&q=index&json=1&limit=99&tags=${query}`); 24 | const data = await response.json(); 25 | const randomInt = Math.floor(Math.random() * (Object.keys(data).length - 0) + 0); 26 | 27 | const postId = data[randomInt]?.id; 28 | 29 | if (!postId) { 30 | await interaction.editReply(`I'm so sorry but I can't find anything with the tag(s) ${italic(query)}`); 31 | return; 32 | } 33 | 34 | const postUrl = `https://lolibooru.moe/post/show/${postId}`; 35 | const imgUrl = data[randomInt].file_url; 36 | const imgUrlEdited = imgUrl.replace(/ /g, '%20'); 37 | 38 | const embed = new EmbedBuilder() 39 | .setTitle(`Post URL`) 40 | .setURL(postUrl) 41 | .setDescription(`Board: lolibooru.moe\nQueried Tag(s): ${query}\nRequested by: ${interaction.member}`) 42 | .setColor(color) 43 | .setImage(imgUrlEdited) 44 | .setFooter({ text:"This content is served by an image-search api and Darling is not responsible for any content!" }); 45 | 46 | await interaction.editReply({ embeds: [embed] }); 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /src/commands/nsfw/hentaineko.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-inner-declarations */ 2 | const { SlashCommandBuilder } = require('@discordjs/builders'); 3 | const { color } = require('../../data/config.json'); 4 | const { EmbedBuilder } = require('discord.js'); 5 | const fetch = require('node-fetch'); 6 | 7 | module.exports = { 8 | data: new SlashCommandBuilder() 9 | .setName('hentaineko') 10 | .setDescription('Returns a random hentai neko pic') 11 | .addStringOption(option => 12 | option.setName('amount') 13 | .setDescription('Defines how many images the bot should send') 14 | .setRequired(true) 15 | .addChoices( 16 | { 17 | name: 'One', 18 | value: '1', 19 | }, 20 | { 21 | name: 'Five', 22 | value: '5', 23 | }, 24 | { 25 | name: 'Ten', 26 | value: '10', 27 | }, 28 | )) 29 | .setDMPermission(false), 30 | 31 | async execute(interaction) { 32 | if (!interaction.channel.nsfw) { 33 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 34 | return; 35 | } 36 | const amount = parseInt(interaction.options.getString('amount')); 37 | 38 | async function fetchImage() { 39 | const response = await fetch('https://api.waifu.pics/nsfw/neko'); 40 | const data = await response.json(); 41 | const img_url = data.url; 42 | return img_url; 43 | } 44 | 45 | const fetches = Array.from(Array(amount), () => fetchImage()); 46 | const images = await Promise.all(fetches); 47 | const embeds = []; 48 | 49 | images.forEach((img) => { 50 | const embed = new EmbedBuilder() 51 | .setColor(color) 52 | .setTitle('Random hentai neko pic?') 53 | .setFooter({ text: 'From waifu.pics' }) 54 | .setImage(img); 55 | embeds.push(embed); 56 | }); 57 | 58 | await interaction.reply({ embeds: embeds }); 59 | }, 60 | }; 61 | -------------------------------------------------------------------------------- /src/commands/nsfw/hentaiblowjob.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-inner-declarations */ 2 | const { SlashCommandBuilder } = require('@discordjs/builders'); 3 | const { color } = require('../../data/config.json'); 4 | const { EmbedBuilder } = require('discord.js'); 5 | const fetch = require('node-fetch'); 6 | 7 | module.exports = { 8 | data: new SlashCommandBuilder() 9 | .setName('hentaiblowjob') 10 | .setDescription('Returns a random hentai blowjob gif') 11 | .addStringOption(option => 12 | option.setName('amount') 13 | .setDescription('Defines how many gifs the bot should send') 14 | .setRequired(true) 15 | .addChoices( 16 | { 17 | name: 'One', 18 | value: '1', 19 | }, 20 | { 21 | name: 'Five', 22 | value: '5', 23 | }, 24 | { 25 | name: 'Ten', 26 | value: '10', 27 | }, 28 | )) 29 | .setDMPermission(false), 30 | 31 | async execute(interaction) { 32 | if (!interaction.channel.nsfw) { 33 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 34 | return; 35 | } 36 | const amount = parseInt(interaction.options.getString('amount')); 37 | 38 | async function fetchImage() { 39 | const response = await fetch('https://api.waifu.pics/nsfw/blowjob'); 40 | const data = await response.json(); 41 | const img_url = data.url; 42 | return img_url; 43 | } 44 | 45 | const fetches = Array.from(Array(amount), () => fetchImage()); 46 | const images = await Promise.all(fetches); 47 | const embeds = []; 48 | 49 | images.forEach((img) => { 50 | const embed = new EmbedBuilder() 51 | .setColor(color) 52 | .setTitle('Random hentai blowjob') 53 | .setFooter({ text: 'From waifu.pics' }) 54 | .setImage(img); 55 | embeds.push(embed); 56 | }); 57 | 58 | await interaction.reply({ embeds: embeds }); 59 | }, 60 | }; 61 | -------------------------------------------------------------------------------- /src/commands/nsfw/hentaiwaifu.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-inner-declarations */ 2 | const { SlashCommandBuilder } = require('@discordjs/builders'); 3 | const { color } = require('../../data/config.json'); 4 | const { EmbedBuilder } = require('discord.js'); 5 | const fetch = require('node-fetch'); 6 | 7 | module.exports = { 8 | data: new SlashCommandBuilder() 9 | .setName('hentaiwaifu') 10 | .setDescription('Returns a random hentai waifu pic') 11 | .addStringOption(option => 12 | option.setName('amount') 13 | .setDescription('Defines how many images the bot should send') 14 | .setRequired(true) 15 | .addChoices( 16 | { 17 | name: 'One', 18 | value: '1', 19 | }, 20 | { 21 | name: 'Five', 22 | value: '5', 23 | }, 24 | { 25 | name: 'Ten', 26 | value: '10', 27 | }, 28 | )) 29 | .setDMPermission(false), 30 | 31 | async execute(interaction) { 32 | if (!interaction.channel.nsfw) { 33 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 34 | return; 35 | } 36 | const amount = parseInt(interaction.options.getString('amount')); 37 | 38 | async function fetchImage() { 39 | const response = await fetch('https://api.waifu.pics/nsfw/waifu'); 40 | const data = await response.json(); 41 | const img_url = data.url; 42 | return img_url; 43 | } 44 | 45 | const fetches = Array.from(Array(amount), () => fetchImage()); 46 | const images = await Promise.all(fetches); 47 | const embeds = []; 48 | 49 | images.forEach((img) => { 50 | const embed = new EmbedBuilder() 51 | .setColor(color) 52 | .setTitle('Random hentai waifu pic?') 53 | .setFooter({ text: 'From waifu.pics' }) 54 | .setImage(img); 55 | embeds.push(embed); 56 | }); 57 | 58 | await interaction.reply({ embeds: embeds }); 59 | }, 60 | }; 61 | -------------------------------------------------------------------------------- /src/events/interaction-create.js: -------------------------------------------------------------------------------- 1 | const logger = require("silly-logger"); 2 | 3 | module.exports = { 4 | name: 'interactionCreate', 5 | once: false, 6 | async execute(interaction) { 7 | if (!interaction.isCommand()) return; 8 | 9 | const command = interaction.client.commands.get(interaction.commandName); 10 | 11 | if (!command) return; 12 | 13 | if (!interaction.guild) return await interaction.reply({ content: "No.", ephemeral: true }); 14 | 15 | if (interaction.commandData == undefined) { 16 | interaction.commandData = { 17 | name: interaction.commandName, 18 | options: [interaction.options], 19 | }; 20 | } 21 | 22 | try { 23 | await command.execute(interaction); 24 | } 25 | catch (error) { 26 | logger.error(error); 27 | try { 28 | try { 29 | await interaction.reply({ content: `There was an error while executing this command!\nJoin the Support Server and send us the error message:\n \`\`\`js\n ${JSON.stringify(interaction.commandData, null, 4)} \`\`\` \`\`\`js\n${error}\`\`\` \n https://discord.com/invite/tpUr7d3 `, embeds: [], ephemeral: true }); 30 | } 31 | catch { 32 | await interaction.editReply({ content: `There was an error while executing this command!\nJoin the Support Server and send us the error message:\n \`\`\`js\n ${JSON.stringify(interaction.commandData, null, 4)} \`\`\` \`\`\`js\n${error}\`\`\` \n https://discord.com/invite/tpUr7d3 `, embeds: [], ephemeral: true }); 33 | } 34 | } 35 | // eslint-disable-next-line no-inline-comments 36 | catch (err) { 37 | logger.error(err); 38 | try { 39 | await interaction.reply({ content: `There was an error while executing this command, but there was another error sending the error message!\n Please contact us and include the following information: \`command name, options, time of execution\` \n https://discord.com/invite/tpUr7d3 `, embeds: [], ephemeral: true }); 40 | } 41 | catch { 42 | await interaction.editReply({ content: `There was an error while executing this command, but there was another error sending the error message!\n Please contact us and include the following information: \`command name, options, time of execution\` \n https://discord.com/invite/tpUr7d3 `, embeds: [], ephemeral: true }); 43 | } 44 | } 45 | } 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /src/commands/boorus/safebooru.js: -------------------------------------------------------------------------------- 1 | const { italic, SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName('safebooru') 9 | .setDescription('search safebooru.org board') 10 | .addStringOption(option => option.setName('tags').setDescription('tags to search for').setRequired(true)) 11 | .setDMPermission(false), 12 | 13 | async execute(interaction) { 14 | if (!interaction.channel.nsfw) { 15 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 16 | return; 17 | } 18 | 19 | await interaction.deferReply(); 20 | const query = interaction.options.getString('tags'); 21 | if (query.split(' ').length > 2) return interaction.editReply({ content: "Max. amount of tags is 2." }); 22 | 23 | const response = await fetch(`https://safebooru.org/index.php?page=dapi&s=post&q=index&json=1&tags=${query}`); 24 | let data; 25 | 26 | try { 27 | data = await response.json(); 28 | } catch { 29 | await interaction.editReply(`I'm so sorry but I can't find anything with the tag(s) ${italic(query)}`); 30 | return; 31 | } 32 | 33 | const randomInt = Math.floor(Math.random() * (Object.keys(data).length - 0) + 0); 34 | 35 | const postImgName = data[randomInt].image; 36 | const postDirectory = data[randomInt].directory; 37 | const postId = data[randomInt].id; 38 | 39 | const postUrl = `https://safebooru.org/index.php?page=post&s=view&id=${postId}`; 40 | const imgUrl = `https://safebooru.org/images/${postDirectory}/${postImgName}`; 41 | 42 | const embed = new EmbedBuilder() 43 | .setTitle(`Post URL`) 44 | .setURL(postUrl) 45 | .setDescription(`Board: safebooru.org\nQueried Tag(s): ${query}\nRequested by: ${interaction.member}`) 46 | .setColor(color) 47 | .setImage(imgUrl) 48 | .setFooter({ text: "This content is served by an image-search api and Darling is not responsible for any content!" }); 49 | 50 | await interaction.editReply({ embeds: [embed] }); 51 | }, 52 | }; 53 | -------------------------------------------------------------------------------- /src/commands/other/whois.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('whois') 8 | .setDescription('returns information about you or') 9 | .addUserOption(option => 10 | option.setName('user') 11 | .setDescription('Tag a user to get information about them')) 12 | .setDMPermission(false), 13 | 14 | async execute(interaction) { 15 | let user = interaction.options.getUser('user'); 16 | if (user === null) { 17 | user = interaction.user; 18 | } 19 | 20 | async function getMemberJoinDate() { 21 | const member = await interaction.guild.members.fetch(user.id); 22 | const date = Math.round(member.joinedTimestamp / 1000); 23 | return date; 24 | } 25 | const joinDate = await getMemberJoinDate(); 26 | 27 | let roles = ''; 28 | async function getMemberRoles() { 29 | const member = await interaction.guild.members.fetch(user.id); 30 | const rolesArray = member._roles; 31 | rolesArray.forEach(role => roles += `<@&${role}> `); 32 | return roles; 33 | } 34 | const memberRoles = await getMemberRoles(); 35 | 36 | const avatar = user.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }); 37 | const embed = new EmbedBuilder() 38 | .setDescription(`<@${user.id}>`) 39 | .setAuthor({ name: String(user.username), iconURL: avatar }) 40 | .setThumbnail(avatar) 41 | .setFooter({ text: `User ID: ${user.id}` }) 42 | .setColor(color) 43 | .addFields( 44 | { name: 'Joined:', value: `\n`, inline: true }, 45 | { name: 'Registered:', value: `\n`, inline: true }, 46 | { name: 'Roles:', value: '\u200b' + memberRoles, inline: false }, 47 | ); 48 | await interaction.reply({ embeds: [embed] }); 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /src/website/views/header.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/commands/other/botinfo.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('botinfo') 8 | .setDescription('Shows some information about the bot') 9 | .setDMPermission(false), 10 | 11 | async execute(interaction) { 12 | const servers = interaction.client.guilds.cache.size; 13 | const eckigerluca = await interaction.client.users.fetch('173374602389618688'); 14 | const eckigerluca_avatar = eckigerluca.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }); 15 | const embed = new EmbedBuilder() 16 | .setTitle('Hey!') 17 | .setColor(color) 18 | .setDescription('This page here is just existing to share some information about the bot, so read it if you have time for it lol') 19 | .setThumbnail(interaction.client.user.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false })) 20 | .addFields( 21 | // { name: 'How it started...', value: "I actually decided to code my own bot because I felt like 'Ugh pay2win I dont like that' sooooo I decided to do it free then. Yes, this bot is completely free, but I have to pay to maintain it tho lol\nThe first few lines of code of `Darling.` were written in Python with discord.py, but sadly this library isn't maintained anymore so I had to switch to `Discord.js` which is obv written in JavaScript. Uh yeah, a date.. it was the 12th August 2020 when I started this project. How time has passed\nEnough bs, time for important information!", inline: false }, 22 | { name: "Profile Picture", value: `__Artist:__\n[ShiChi](https://www.pixiv.net/en/users/36083362)\n__Artwork:__\n[スカジ](https://www.pixiv.net/en/artworks/85612659)`, inline: true }, 23 | { name: "Servers", value: `${servers}`, inline: true }, 24 | { name: "Code", value: "https://github.com/eckigerluca/darling", inline: true }, 25 | { name: "Support", value: "The **Bot Support** is on my [Server](https://eckigerluca.com/discord).\nBut you can also support **me** on [Patreon](https://patreon.com/eckigerluca) or [Ko-Fi](https://ko-fi.com/eckigerluca)", inline: false }, 26 | ) 27 | .setFooter({ text: `Bot by ${eckigerluca.username}`, iconURL: eckigerluca_avatar }) 28 | .setAuthor({ name: "EckigerLuca", iconURL: eckigerluca_avatar, url: "https://github.com/EckigerLuca/" }); 29 | await interaction.reply({ embeds: [embed] }); 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Darling. 2 | 3 | 4 | 5 | 6 | 7 | ### This is the code of my bot 8 | So I'd prefer if You would just add it to your server with [this](https://eckigerluca.com/darling/invite) link. 9 | 10 | ### But if You want to host it by yourself, 11 | rename the `config.json.public` to `config.json` (found under `src/data`) and edit the values. The Bot **needs** the `SERVER MEMBERS INTENT`, so make sure to enable it! 12 | 13 | Make sure that you have a mongo-db database avaiable for bot! The name of the database needs to be `darling`. On first start, the bot will create the needed collection on it's own. [Install MongoDB](https://www.mongodb.com/docs/v6.0/administration/install-community/) (Currently using v6.0) 14 | 15 | New with Version 2.0 is a Web Dashboard, which can't be disabled!
16 | Set it up by renaming the `settings.json.public` (found under `src/website`) to `settings.json` and changing the values in the as needed. Client ID and Secret are found at the OAuth2 Section of your Application. You also need to add your Domain and Callback URL to the Redirects. 17 | 18 | After that, use `npm i` to install all needed packages. When done, register the slash commands by using `npm run deploy` in your console. 19 | 20 | You can then start the bot with `npm start` or `node .` 21 | 22 | If the bot is online, invite it to the server You want to use it on and check if the Dashboard works. (Check the image for permissions). 23 | 24 | ![img](https://user-images.githubusercontent.com/63116530/133927732-7ad6a8e1-86cb-4ece-8753-ec69be1b370c.png) 25 | If the Bot won't start, check the console for any errors and if there are one's, create an Issue (or try to fix them by yourself). 26 | 27 | ## Top.gg 28 | This bot uses Top.gg. If you don't want to use it, leave the variable `topGG` in the `config.json` as it is, but if you want to use it change the bool to `true` and PLEASE DO NOT forget to add your token in the file! 29 | 30 | ## Contact: 31 | * [E-Mail](mailto:contact@darling-bot.xyz) 32 | * Discord: `EckigerLuca#0001` 33 | * Support [Server](https://eckigerluca.com/discord) 34 | 35 | ## 36 | 37 | -------------------------------------------------------------------------------- /src/commands/boorus/rule34.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-inner-declarations */ 2 | const { italic, SlashCommandBuilder } = require('@discordjs/builders'); 3 | const { color } = require('../../data/config.json'); 4 | const { EmbedBuilder } = require('discord.js'); 5 | const fetch = require('node-fetch'); 6 | 7 | module.exports = { 8 | data: new SlashCommandBuilder() 9 | .setName('rule34') 10 | .setDescription('search rule34.xxx board') 11 | .addStringOption(option => option.setName('tags').setDescription('tags to search for').setRequired(true)) 12 | .setDMPermission(false), 13 | 14 | async execute(interaction) { 15 | if (interaction.channel.nsfw) { 16 | await interaction.deferReply(); 17 | const query = interaction.options.getString('tags'); 18 | if (query.split(' ').length > 2) return interaction.editReply({ content: "Max. amount of tags is 2." }); 19 | 20 | async function getBooru() { 21 | const response = await fetch(`https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&tags=${query}`); 22 | let data; 23 | try { 24 | data = await response.json(); 25 | const randomInt = Math.floor(Math.random() * (Object.keys(data).length - 0) + 0); 26 | 27 | const postId = data[randomInt].id; 28 | 29 | const postUrl = `https://rule34.xxx/index.php?page=post&s=view&id=${postId}`; 30 | const imgUrl = data[randomInt].file_url; 31 | 32 | const result = { 33 | "postUrl": postUrl, 34 | "imgUrl": imgUrl, 35 | }; 36 | return result; 37 | } catch { 38 | return; 39 | } 40 | } 41 | let booruResult; 42 | 43 | do { 44 | booruResult = await getBooru(); 45 | if (!booruResult) { 46 | interaction.editReply(`I'm so sorry but I can't find anything with the tag(s) ${italic(query)}`); 47 | return; 48 | } 49 | } while (booruResult.imgUrl.includes('mp4')); 50 | 51 | const embed = new EmbedBuilder() 52 | .setTitle(`Post URL`) 53 | .setURL(booruResult.postUrl) 54 | .setDescription(`Board: rule34.xxx\nQueried Tag(s): ${query}\nRequested by: ${interaction.member}`) 55 | .setColor(color) 56 | .setImage(booruResult.imgUrl) 57 | .setFooter({ text: "This content is served by an image-search api and Darling is not responsible for any content!" }); 58 | 59 | await interaction.editReply({ embeds: [embed] }); 60 | } 61 | else { 62 | await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); 63 | } 64 | }, 65 | }; 66 | -------------------------------------------------------------------------------- /src/commands/moderation/kick.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js'); 2 | 3 | module.exports = { 4 | data: new SlashCommandBuilder() 5 | .setName('kick') 6 | .setDescription('kick a member') 7 | .addUserOption(option => option.setName('user').setDescription('Select a user to kick').setRequired(true)) 8 | .addStringOption(option => option.setName('reason').setDescription('Define a reason').setRequired(false)) 9 | .setDefaultMemberPermissions(PermissionFlagsBits.KickMembers) 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | const user = interaction.options.getUser('user'); 14 | const reason = interaction.options.getString('reason') || "No reason provided."; 15 | const member = await interaction.guild.members.fetch(user.id); 16 | const messageAuthor = await interaction.guild.members.fetch(interaction.member.id); 17 | const authorIsServerOwner = messageAuthor.id === interaction.guild.ownerId; 18 | const clientMember = interaction.guild.members.me; 19 | 20 | if (!clientMember.permissions.has(PermissionFlagsBits.KickMembers)) { 21 | await interaction.reply({ content: "I am missing permission to do that!", ephemeral: true }); 22 | return; 23 | } 24 | else if (!messageAuthor.permissions.has(PermissionFlagsBits.KickMembers)) { 25 | await interaction.reply({ content: "You're not allowed to do that!", ephemeral: true }); 26 | return; 27 | } 28 | 29 | if (clientMember === member) { 30 | await interaction.reply({ content: "I can't kick myself silly!", ephemeral: true }); 31 | return; 32 | } 33 | else if (member.id === interaction.guild.ownerId) { 34 | await interaction.reply({ content: "You can't kick the server owner silly!", ephemeral: true }); 35 | return; 36 | } 37 | 38 | if (member.roles.highest.position >= clientMember.roles.highest.position) { 39 | await interaction.reply({ content: "I can't kick that member because their role is higher than mine!", ephemeral: true }); 40 | return; 41 | } 42 | else if (member.roles.highest.position >= messageAuthor.roles.highest.position && !authorIsServerOwner) { 43 | await interaction.reply({ content: "You can't kick that member because their role is higher than yours!", ephemeral: true }); 44 | return; 45 | } 46 | 47 | try { 48 | await member.send(`You have been kicked from **${interaction.guild.name}**\nReason: ${reason}`); 49 | } 50 | catch { 51 | console.log("Could not dm kicked member"); 52 | } 53 | 54 | await member.kick(reason); 55 | interaction.reply({ content: `Kicked ${member.username} successfully!\nReason: ${reason}` }); 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /src/commands/moderation/ban.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js'); 2 | 3 | module.exports = { 4 | data: new SlashCommandBuilder() 5 | .setName('ban') 6 | .setDescription('ban a member') 7 | .addUserOption(option => option.setName('user').setDescription('Select a user to ban').setRequired(true)) 8 | .addStringOption(option => option.setName('reason').setDescription('Define a reason').setRequired(false)) 9 | .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers) 10 | .setDMPermission(false), 11 | 12 | async execute(interaction) { 13 | const user = interaction.options.getUser('user'); 14 | const reason = interaction.options.getString('reason') || "No reason provided."; 15 | const member = await interaction.guild.members.fetch(user.id); 16 | const messageAuthor = await interaction.guild.members.fetch(interaction.member.id); 17 | const authorIsServerOwner = messageAuthor.id === interaction.guild.ownerId; 18 | const clientMember = interaction.guild.members.me; 19 | 20 | if (!clientMember.permissions.has(PermissionFlagsBits.BanMembers)) { 21 | await interaction.reply({ content: "I am missing permission to do that!", ephemeral: true }); 22 | return; 23 | } 24 | else if (!messageAuthor.permissions.has(PermissionFlagsBits.BanMembers)) { 25 | await interaction.reply({ content: "You're not allowed to do that!", ephemeral: true }); 26 | return; 27 | } 28 | 29 | if (clientMember === member) { 30 | await interaction.reply({ content: "I can't ban myself silly!", ephemeral: true }); 31 | return; 32 | } 33 | else if (member.id === interaction.guild.ownerId) { 34 | await interaction.reply({ content: "You can't ban the server owner silly!", ephemeral: true }); 35 | return; 36 | } 37 | 38 | if (member.roles.highest.position >= clientMember.roles.highest.position) { 39 | await interaction.reply({ content: "I can't ban that member becuse their role is higher than mine!", ephemeral: true }); 40 | return; 41 | } 42 | else if (member.roles.highest.position >= messageAuthor.roles.highest.position && !authorIsServerOwner) { 43 | await interaction.reply({ content: "You can't ban that member because their role is higher than yours!", ephemeral: true }); 44 | return; 45 | } 46 | 47 | try { 48 | await member.send(`You have been banned from **${interaction.guild.name}**\nReason: ${reason}`); 49 | } 50 | catch { 51 | console.log("Could not dm member after banning!"); 52 | } 53 | 54 | await member.ban({ reason: reason }); 55 | interaction.reply({ content: `Banned ${member.user.username} successfully!\nReason: ${reason}` }); 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { Client, Collection, GatewayIntentBits } = require('discord.js'); 3 | const { token, mongodbUri } = require('./data/config.json'); 4 | const { MongoClient } = require('mongodb'); 5 | const logger = require('silly-logger'); 6 | 7 | logger.enableLogFiles(true); 8 | logger.logFolderPath('./src/logs'); 9 | 10 | const { topGG } = require('./data/config.json'); 11 | 12 | const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers] }); 13 | client.commands = new Collection(); 14 | 15 | const dbClient = new MongoClient(String(mongodbUri)); 16 | (async function dbSetup() { 17 | await dbClient.connect(); 18 | client.dbClient = dbClient; 19 | logger.success("Connected to database server!"); 20 | 21 | try { 22 | const databases = (await dbClient.db().admin().listDatabases()).databases; 23 | let found = false; 24 | databases.forEach((database) => { 25 | if (database.name === "darling") found = true; 26 | }); 27 | if (!found) { 28 | throw new Error("Database not existing!"); 29 | } 30 | } 31 | catch (err) { 32 | logger.error("Database not existing! Please create a mongodb database called 'darling' and restart the bot!"); 33 | process.exit(1); 34 | } 35 | 36 | const requiredCollections = ['servers', 'users', 'welcome']; 37 | const collections = await dbClient.db("darling").listCollections().toArray(); 38 | const collectionsOnServer = []; 39 | const notFound = []; 40 | 41 | collections.forEach((collection) => { 42 | collectionsOnServer.push(collection.name); 43 | }); 44 | 45 | requiredCollections.forEach((collection) => { 46 | if (!collectionsOnServer.includes(collection)) notFound.push(collection); 47 | }); 48 | 49 | if (notFound.length > 0) { 50 | logger.error(`Missing collections: ${notFound.join(', ')}`); 51 | logger.info("Creating missing collections..."); 52 | notFound.forEach(async (collection) => { 53 | dbClient.db("darling").createCollection(collection); 54 | logger.info(`Created collection ${collection}!`); 55 | }); 56 | } 57 | logger.success("Database setup complete!\n"); 58 | 59 | } ()); 60 | 61 | if (topGG) { 62 | const { discordBotListToken } = require('./data/config.json'); 63 | const { AutoPoster } = require('topgg-autoposter'); 64 | const ap = AutoPoster(`${String(discordBotListToken)}`, client); 65 | 66 | ap.on('posted', (stats) => { 67 | logger.success(`Posted stats to Top.gg | ${stats.serverCount} servers`); 68 | }); 69 | 70 | ap.on('error', (err) => { 71 | logger.error(err); 72 | }); 73 | } 74 | 75 | const folders = fs.readdirSync('./src/commands'); 76 | 77 | for (const folder of folders) { 78 | const files = fs.readdirSync(`./src/commands/${folder}`); 79 | for (const file of files) { 80 | const command = require(`./commands/${folder}/${file}`); 81 | client.commands.set(command.data.name, command); 82 | } 83 | } 84 | 85 | const eventFiles = fs.readdirSync('./src/events').filter(file => file.endsWith('.js')); 86 | for (const file of eventFiles) { 87 | const event = require(`./events/${file}`); 88 | if (event.once) { 89 | client.once(event.name, (...args) => event.execute(...args)); 90 | } 91 | else { 92 | client.on(event.name, (...args) => event.execute(...args)); 93 | } 94 | } 95 | 96 | client.login(token); 97 | -------------------------------------------------------------------------------- /src/events/guild-member-add.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder } = require('discord.js'); 2 | const { MongoClient } = require('mongodb'); 3 | const logger = require('silly-logger'); 4 | const { mongodbUri } = require('../data/config.json'); 5 | 6 | const dbClient = new MongoClient(String(mongodbUri)); 7 | 8 | module.exports = { 9 | name: 'guildMemberAdd', 10 | once: false, 11 | async execute(member) { 12 | if (member.user.bot) return; 13 | const guildId = member.guild.id; 14 | const filter = { 15 | _id: guildId, 16 | }; 17 | try { 18 | await dbClient.connect(); 19 | const db = dbClient.db("darling"); 20 | const collection = db.collection("welcome"); 21 | const result = await collection.findOne(filter); 22 | const eckigerluca = await member.client.users.fetch('173374602389618688'); 23 | const eckigerluca_avatar = eckigerluca.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }); 24 | if (result) { 25 | if (result.enabled == true) { 26 | const memberMention = `<@${member.user.id}>`; 27 | const memberName = member.displayName; 28 | const memberNumber = member.guild.memberCount; 29 | const serverName = member.guild.name; 30 | 31 | result.headline = result.headline.replaceAll("${memberName}", memberName); 32 | result.headline = result.headline.replaceAll("${memberNumber}", memberNumber); 33 | result.headline = result.headline.replaceAll("${serverName}", serverName); 34 | 35 | result.message = result.message.replaceAll("${memberMention}", memberMention); 36 | result.message = result.message.replaceAll("${memberName}", memberName); 37 | result.message = result.message.replaceAll("${memberNumber}", memberNumber); 38 | result.message = result.message.replaceAll("${serverName}", serverName); 39 | 40 | result.dm[1] = result.dm[1].replaceAll("${memberMention}", memberMention); 41 | result.dm[1] = result.dm[1].replaceAll("${memberName}", memberName); 42 | result.dm[1] = result.dm[1].replaceAll("${memberNumber}", memberNumber); 43 | result.dm[1] = result.dm[1].replaceAll("${serverName}", serverName); 44 | 45 | const embed = new EmbedBuilder() 46 | .setTitle(result.headline) 47 | .setDescription(result.message) 48 | .setFooter({ text: `Bot by ${eckigerluca.username}`, iconURL: eckigerluca_avatar }) 49 | .setTimestamp() 50 | .setColor(result.color); 51 | 52 | if (result.thumbnail == true) { 53 | embed.setThumbnail(member.displayAvatarURL({ size: 512, extension: 'png', forceStatic: false })); 54 | } 55 | if (result.image[0] == true) { 56 | embed.setImage(result.image[1]); 57 | } 58 | 59 | if (result.role[0] == true) { 60 | try { 61 | const role = await member.guild.roles.fetch(result.role[1]); 62 | await member.roles.add(role); 63 | } catch (err) { 64 | logger.error(err); 65 | } 66 | } 67 | 68 | try { 69 | const channel = await member.guild.channels.fetch(result.channelId); 70 | 71 | if (channel) await channel.send({ content: memberMention, embeds: [embed] }); 72 | } catch (err) { 73 | logger.error(err); 74 | } 75 | 76 | if (result.dm[0] == true) { 77 | const dmChannel = await member.user.createDM(); 78 | await dmChannel.send({ content: result.dm[1] }); 79 | } 80 | } 81 | } 82 | } 83 | catch (err) { 84 | logger.error(err); 85 | } 86 | }, 87 | }; 88 | -------------------------------------------------------------------------------- /src/events/birthday-checker.js: -------------------------------------------------------------------------------- 1 | const logger = require('silly-logger'); 2 | const { scheduleJob, RecurrenceRule } = require('node-schedule'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const { color } = require('../data/config.json'); 5 | 6 | const rule = new RecurrenceRule(); 7 | rule.tz = 'Etc/UTC'; 8 | // run at 12:00 UTC 9 | rule.hour = 12; 10 | rule.minute = 0; 11 | 12 | module.exports = { 13 | name: 'ready', 14 | once: true, 15 | async execute(client) { 16 | logger.success("Birthday checker started!"); 17 | const eckigerluca = await client.users.fetch('173374602389618688'); 18 | const eckigerluca_avatar = eckigerluca.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }); 19 | 20 | scheduleJob(rule, async () => { 21 | logger.info("Checking birthdays..."); 22 | const now = new Date(); 23 | const db = client.dbClient.db("darling"); 24 | const userCollection = db.collection("users"); 25 | 26 | let day = now.getUTCDate(); 27 | if (day < 10) day = `0${day}`; 28 | let month = now.getUTCMonth() + 1; 29 | if (month < 10) month = `0${month}`; 30 | 31 | const query = { birthday: { $eq: `${day}/${month}` } }; 32 | 33 | const results = await userCollection.find(query).toArray(); 34 | 35 | results.forEach(async (result) => { 36 | const updateDoc = { 37 | $inc: { 38 | money: 10000, 39 | }, 40 | }; 41 | if (result.money !== "∞") await userCollection.updateOne({ _id: result._id }, updateDoc); 42 | const user = await client.users.fetch(result._id); 43 | 44 | const embed = new EmbedBuilder() 45 | .setTitle(`Happy birthday!`) 46 | .setDescription(`Woah! It's your birthday today. Happy birthday!\nHave a wonderful day, get many presents and eat a lot of cake!\nFrom me, you will receive 10.000 ${String.fromCodePoint(0x1FA99)}!`) 47 | .setTimestamp() 48 | .setThumbnail(user.displayAvatarURL({ forceStatic: false, format: 'png', size: 1024 })) 49 | .setColor(color); 50 | user.send({ embeds: [embed] }); 51 | 52 | const serverCollection = db.collection("servers"); 53 | const filter = { "birthday.enabled": true }; 54 | const servers = await serverCollection.find(filter).toArray(); 55 | servers.forEach(async (server) => { 56 | const guild = await client.guilds.fetch(server._id); 57 | const channel = guild.channels.cache.get(server.birthday.channel); 58 | if (!channel) return; 59 | 60 | let rawMessage = `Hey, it's ${user}'s birthday today!\nMake sure to gratulate them!`; 61 | let birthdayEmbedDescription; 62 | if (server.birthday.customMessage.enabled) rawMessage = server.birthday.customMessage.message; 63 | birthdayEmbedDescription = rawMessage.replaceAll("${memberMention}", user); 64 | birthdayEmbedDescription = birthdayEmbedDescription.replaceAll("${memberName}", user.username); 65 | 66 | const birthdayEmbed = new EmbedBuilder() 67 | .setTitle(`Happy birthday, ${user.username}!`) 68 | .setDescription(birthdayEmbedDescription) 69 | .setThumbnail(user.displayAvatarURL({ forceStatic: false, format: 'jpg', size: 1024 })) 70 | .setFooter({ text: `Bot by ${eckigerluca.username}`, iconURL: eckigerluca_avatar }) 71 | .setColor(color); 72 | 73 | channel.send({ content: `${user}`, embeds: [birthdayEmbed] }); 74 | }); 75 | }); 76 | 77 | logger.success(`Checked birthdays! ${results.length} birthdays today.`); 78 | }); 79 | }, 80 | }; 81 | -------------------------------------------------------------------------------- /src/website/views/terms-of-service.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Darling. | Terms of Service 16 | 17 | 25 | 26 | 27 |
28 | <%- await include('header.ejs'); %> 29 |
30 |
31 |
32 |

Terms of Service

33 |
34 |

By inviting Darling. to your Discord Server or logging into our website (https://darling-bot.xyz) you agree that you have read, understood and accepted these terms. You are also responsible for informing the members in your Discord Server about these terms. If you do not agree with any of these terms, you are prohibited from using or adding any version of Darling. to your server.

35 | 36 |

Disclaimer

37 |

38 | You are strictly prohibited from using Darling. against the Terms of Service of Discord or for illegal purposes. We are doing our best to prevent these activities, while trying to provide the best user experience as possible. If you find people or communities using Darling. against the ToS of Discord or even for illegal activities, please send us an E-Mail to contact@darling-bot.xyz 39 |

40 | 41 |

Proprietary Rights

42 |

43 | We (Darling. or more specifically <%- legalName %>) own and retain all rights for public available data. We grant you the permission to use this available data for your own needs, but strictly disallow any commercial use. You therefore shall not sell, license or otherwise commercialize the data except if the permission was expressly granted to you. 44 |

45 | 46 |

Availability

47 |
    48 |
  • Darling. is provided as-is. There are no guarantees that it will be available in the future, and its purpose or availability may be changed at any time.
  • 49 |
  • User related data may be deleted at any time.
  • 50 |
  • User related data is non-transferable between Discord Accounts.
  • 51 |
  • Access to all or specific features of Darling. may be revoked, for all or a specific user, at any time.
  • 52 |
53 | 54 |

Last Updated: 03.01.2023

55 |
56 |
57 |
58 |
59 |
60 | <%- await include('footer.ejs'); %> 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/website/views/footer.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/website/views/dashboard/settings.ejs: -------------------------------------------------------------------------------- 1 | 2 | <% 3 | let toggle; 4 | const dbClient = bot.dbClient; 5 | const db = dbClient.db("darling"); 6 | const collection = db.collection("welcome"); 7 | const filter = { 8 | _id: guild.id, 9 | }; 10 | const checkResult = await collection.findOne(filter); 11 | if (checkResult == null) { 12 | toggle = ""; 13 | } else { 14 | if (checkResult.enabled == true) { 15 | toggle = "checked"; 16 | } else { 17 | toggle = ""; 18 | } 19 | } 20 | %> 21 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Darling. | <%- guild.name %>'s Dashboard 45 | 61 | 62 | <%- await include('sidebar.ejs'); %> 63 |
64 |
65 |

Welcome to the Dashboard!

66 |
67 | From here, you can manage some of the bot's features. 68 |
69 | Click on the name of the function to manage them. You can enable/disable them here too! 70 |
71 |
72 |
73 |
74 |
75 |
76 |

77 | 80 |

81 |
82 |
83 |
84 | 89 |
90 |
91 |
92 | > 93 | 94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | <%- await include('../error.ejs') %> 104 |
-------------------------------------------------------------------------------- /src/commands/moderation/serverstats.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder, ChannelType } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('serverstats') 8 | .setDescription('Shows some information about the server') 9 | .setDMPermission(false), 10 | 11 | async execute(interaction) { 12 | const guild = interaction.guild; 13 | 14 | async function getTextChannels() { 15 | const all_channels = await interaction.guild.channels.fetch(); 16 | const text_channels = all_channels.filter(channels => channels.type === ChannelType.GuildText).size; 17 | return text_channels; 18 | } 19 | 20 | async function getVoiceChannels() { 21 | const all_channels = await interaction.guild.channels.fetch(); 22 | const voice_channels = all_channels.filter(channels => channels.type === ChannelType.GuildVoice).size; 23 | return voice_channels; 24 | } 25 | 26 | async function getRealMembers() { 27 | const all_members = await interaction.guild.members.fetch(); 28 | const humans = all_members.sweep(member => !member.user.bot); 29 | return humans; 30 | } 31 | 32 | async function getBotMembers() { 33 | const all_members = await interaction.guild.members.fetch(); 34 | const bots = all_members.sweep(member => member.user.bot); 35 | return bots; 36 | } 37 | 38 | async function getGuildEmotes() { 39 | const all_emojis = await guild.emojis.fetch(); 40 | const amount = all_emojis.size; 41 | return amount; 42 | } 43 | 44 | async function getGuildRoles() { 45 | const all_roles = await guild.roles.fetch(); 46 | const amount = all_roles.size; 47 | return amount; 48 | } 49 | 50 | const fetches = [ 51 | getTextChannels(), 52 | getVoiceChannels(), 53 | getRealMembers(), 54 | getBotMembers(), 55 | getGuildEmotes(), 56 | getGuildRoles(), 57 | ]; 58 | const resolves = await Promise.all(fetches); 59 | 60 | // order must match with fetches array 61 | const no_text_channels = resolves[0]; 62 | const no_voice_channels = resolves[1]; 63 | const real_members = resolves[2]; 64 | const bot_members = resolves[3]; 65 | const emotes = resolves[4]; 66 | const roles = resolves[5]; 67 | 68 | const boosts = guild.premiumSubscriptionCount; 69 | const members = guild.memberCount; 70 | const date_created = guild.createdTimestamp; 71 | const afk_timeout = guild.afkTimeout / 60; 72 | const afk_channel = guild.afkChannel ?? 'None'; 73 | 74 | const embed = new EmbedBuilder() 75 | .setColor(color) 76 | .setThumbnail(guild.iconURL()) 77 | .setTitle('Stats of the Server') 78 | .addFields( 79 | { name: '_General Information_', value: `**» Name:** ${guild.name}\n**» Created at:** \n**» Owner:** <@${guild.ownerId}>\n**» Guild-ID:** ${guild.id}` }, 80 | { name: '_Members_', value: `**» Total Members:** ${members}\n**» Real Members:** ${real_members}\n**» Bots:** ${bot_members}` }, 81 | { name: '_Channels_', value: `**» Voice Channels:** ${no_voice_channels}\n**» Text Channels:** ${no_text_channels}\n**» AFK Channel:** ${afk_channel}\n**» AFK Timeout:** ${afk_timeout} minutes` }, 82 | { name: '_Other_', value: `**» Roles:** ${roles}\n**» Emotes:** ${emotes}\n**» Boosts:** ${boosts}` }, 83 | ) 84 | .setTimestamp(); 85 | await interaction.reply({ embeds: [embed] }); 86 | }, 87 | }; 88 | -------------------------------------------------------------------------------- /src/commands/welcome/welcome.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder, PermissionsBitField, PermissionFlagsBits } = require('discord.js'); 4 | const { website } = require('../../website/settings.json'); 5 | 6 | module.exports = { 7 | data: new SlashCommandBuilder() 8 | .setName("welcome") 9 | .setDescription("Welcome Function Commands") 10 | .addSubcommand(subcommand => 11 | subcommand 12 | .setName("setup") 13 | .setDescription("Set up the welcome function for your server")) 14 | .addSubcommand(subcommand => 15 | subcommand 16 | .setName("enable") 17 | .setDescription("Enable the welcome function on your server")) 18 | .addSubcommand(subcommand => 19 | subcommand 20 | .setName("disable") 21 | .setDescription("Disable the welcome function on your server")) 22 | .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) 23 | .setDMPermission(false), 24 | 25 | async execute(interaction) { 26 | const dbClient = interaction.client.dbClient; 27 | await interaction.deferReply({ ephemeral: true }); 28 | if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { return await interaction.editReply({ content: "You're not allowed to do that!", ephemeral: true }); } 29 | const subcommand = await interaction.options.getSubcommand(); 30 | switch (subcommand) { 31 | case "setup": { 32 | const embed = new EmbedBuilder() 33 | .setTitle("Welcome Setup") 34 | .setDescription(`Set up the welcome function via the dashboard [here](${website.domain}/dashboard/${interaction.guild.id}/welcome).`) 35 | .setColor(color); 36 | await interaction.editReply({ embeds: [embed] }); 37 | break; 38 | } 39 | case "enable": { 40 | const db = dbClient.db("darling"); 41 | const welcomeCollection = db.collection("welcome"); 42 | const guildId = interaction.guild.id; 43 | const filter = { 44 | _id: guildId, 45 | }; 46 | const checkResult = await welcomeCollection.findOne(filter); 47 | if (checkResult == null) {return await interaction.editReply({ content: "Your server is not existing in the database. Use `/welcome setup` to set up the welcome function.", ephemeral: true });} 48 | const updateDocument = { 49 | $set: { 50 | "enabled": true, 51 | }, 52 | }; 53 | await welcomeCollection.updateOne(filter, updateDocument); 54 | await interaction.editReply({ content: "Successfully enabled the welcome function on your server!", ephemeral: true }); 55 | break; 56 | } 57 | case "disable": { 58 | const db = dbClient.db("darling"); 59 | const welcomeCollection = db.collection("welcome"); 60 | const guildId = interaction.guild.id; 61 | const filter = { 62 | _id: guildId, 63 | }; 64 | const checkResult = await welcomeCollection.findOne(filter); 65 | if (checkResult == null) {return await interaction.editReply({ content: "Your server is not existing in the database. Use `/welcome setup` to set up the welcome function.", ephemeral: true });} 66 | const updateDocument = { 67 | $set: { 68 | "enabled": false, 69 | }, 70 | }; 71 | await welcomeCollection.updateOne(filter, updateDocument); 72 | await interaction.editReply({ content: "Successfully disabled the welcome function on your server!", ephemeral: true }); 73 | break; 74 | } 75 | } 76 | }, 77 | }; 78 | -------------------------------------------------------------------------------- /src/website/views/dashboard/sidebar.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 32 | 33 | 34 | 35 | 43 | 44 |
45 |
46 | 102 |
103 |
104 | 105 | -------------------------------------------------------------------------------- /src/commands/profile/divorce.js: -------------------------------------------------------------------------------- 1 | const { color } = require('../../data/config.json'); 2 | const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); 3 | 4 | function sleep(ms) { 5 | return new Promise(resolve => setTimeout(resolve, ms)); 6 | } 7 | 8 | module.exports = { 9 | data: new SlashCommandBuilder() 10 | .setName('divorce') 11 | .setDescription('End your marriage :/') 12 | .setDMPermission(false), 13 | 14 | async execute(interaction) { 15 | await interaction.deferReply({ ephemeral: true }); 16 | const dbClient = interaction.client.dbClient; 17 | const db = dbClient.db('darling'); 18 | const userCollection = db.collection('users'); 19 | const user = interaction.member.user; 20 | const userDocument = await userCollection.findOne({ '_id': user.id }); 21 | const partnerDocument = await userCollection.findOne({ '_id': userDocument.married.partner }); 22 | const partner = await interaction.client.users.fetch(partnerDocument['_id']); 23 | 24 | const userDivorceConfirmationEmbed = new EmbedBuilder() 25 | .setTitle('Divorce Confirmation') 26 | .setDescription(`Are you sure, that you want to end your marriage with ${partner}?\nClick one of the buttons below to confirm. Starting now, you have 30 seconds to decide.`) 27 | .setThumbnail(partner.displayAvatarURL({ forceStatic: false })) 28 | .setColor(color) 29 | .setTimestamp(); 30 | 31 | const userConfirmRow = new ActionRowBuilder() 32 | .addComponents( 33 | new ButtonBuilder() 34 | .setCustomId('divorce_cancel') 35 | .setEmoji('1061678468380774440') 36 | .setStyle(ButtonStyle.Success), 37 | new ButtonBuilder() 38 | .setCustomId('divorce_confirm') 39 | .setEmoji('1061678465914507386') 40 | .setStyle(ButtonStyle.Danger), 41 | ); 42 | 43 | await interaction.editReply({ embeds: [userDivorceConfirmationEmbed], components: [userConfirmRow], ephemeral: true }); 44 | 45 | let userActed = false; 46 | interaction.client.once("interactionCreate", async (newUserInteraction) => { 47 | if (!newUserInteraction.isButton()) return; 48 | if (newUserInteraction.user.id != interaction.member.user.id) return; 49 | if (newUserInteraction.customId == "divorce_confirm") { 50 | const updateDocument = { 51 | $set: { 52 | married: { 53 | status: false, 54 | partner: null, 55 | date: null, 56 | }, 57 | }, 58 | }; 59 | 60 | await userCollection.updateOne(userDocument, updateDocument); 61 | await userCollection.updateOne(partnerDocument, updateDocument); 62 | 63 | const userConfirmEmbed = new EmbedBuilder() 64 | .setTitle("Divorce Confirmed") 65 | .setDescription(`You have ended your marriage with ${partner}.`) 66 | .setColor(color) 67 | .setTimestamp(); 68 | 69 | const partnerDivorceEmbed = new EmbedBuilder() 70 | .setTitle("Your marriage has ended") 71 | .setDescription(`You are now divorced from ${interaction.user}. They decided to end the marriage.`) 72 | .setColor(color) 73 | .setTimestamp(); 74 | 75 | 76 | userActed = true; 77 | await interaction.editReply({ embeds: [userConfirmEmbed], components: [], ephemeral: true }); 78 | 79 | try { 80 | return await partner.send({ embeds: [partnerDivorceEmbed] }); 81 | } catch { 82 | return await interaction.followUp({ content: `${partner}\nCouldn't DM you!\nPlease allow DMs from server members in your \`Privacy & Safety\` settings!`, embeds: [partnerDivorceEmbed], ephemeral: true }); 83 | } 84 | 85 | } else if (newUserInteraction.customId == "divorce_cancel") { 86 | const userCancelEmbed = new EmbedBuilder() 87 | .setTitle("Divorce Cancelled") 88 | .setDescription(`You have cancelled the divorce.`) 89 | .setColor(color) 90 | .setTimestamp(); 91 | 92 | userActed = true; 93 | return await interaction.editReply({ embeds: [userCancelEmbed], components: [], ephemeral: true }); 94 | } 95 | }); 96 | 97 | await sleep(30_000); 98 | if (userActed) return; 99 | const userTimeoutEmbed = new EmbedBuilder() 100 | .setTitle("Divorce Cancelled") 101 | .setDescription(`You have not confirmed the divorce in time.`) 102 | .setColor(color) 103 | .setTimestamp(); 104 | 105 | return await interaction.editReply({ embeds: [userTimeoutEmbed], components: [], ephemeral: true }); 106 | }, 107 | }; 108 | -------------------------------------------------------------------------------- /src/website/views/dashboard/dashboard.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Darling. | Dashboard 13 | 25 | 26 | 27 | 28 | <%- await include('../header.ejs'); %> 29 |
30 |
31 |

Dashboard

32 |
33 |
34 |

35 | With the Dashboard you can manage the Settings of each single guild! 36 |

37 |
38 | 39 | <% if (user && user.id) { %> 40 |
41 | <% 42 | let guilds = { 43 | "onGuild": [], 44 | "notOnGuild": [], 45 | }; 46 | const allBotGuilds = await bot.guilds.fetch() 47 | user.guilds.filter(guild => { 48 | if (new Permissions(guild.permissions_new).has(Permissions.Flags.Administrator)) return guild; 49 | }).forEach(guild => { 50 | if (allBotGuilds.has(guild.id)) { 51 | guilds["onGuild"].push(guild); 52 | } else { 53 | guilds["notOnGuild"].push(guild); 54 | } 55 | }); 56 | %> 57 | <% guilds["onGuild"].forEach(guild => { %> 58 |
59 |
60 | 61 | <%- guild.icon ? `` : `` %> 62 |
63 |
    64 |
  • 65 |
    <%= guild.name %>
    66 |
  • 67 |
  • 68 | 73 |
  • 74 |
75 |
76 |
77 |
78 | <% }) %> 79 | <% guilds["notOnGuild"].forEach(guild => { %> 80 |
81 |
82 | 83 | <%- guild.icon ? `` : `` %> 84 |
85 |
    86 |
  • 87 |
    <%= guild.name %>
    88 |
  • 89 |
  • 90 | 95 |
  • 96 |
97 |
98 |
99 |
100 | <% }) %> 101 |
102 | <% } else { %> 103 |

Please login first!

104 | <% } %> 105 |
106 | 107 | <%- await include('../error.ejs'); %> 108 | -------------------------------------------------------------------------------- /src/commands/help/help.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | 5 | module.exports = { 6 | data: new SlashCommandBuilder() 7 | .setName('help') 8 | .setDescription('Shows all commands') 9 | .setDMPermission(false), 10 | 11 | async execute(interaction) { 12 | const eckigerluca = await interaction.client.users.fetch('173374602389618688'); 13 | const eckigerluca_avatar = eckigerluca.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }); 14 | const embed = new EmbedBuilder() 15 | .setColor(color) 16 | .setTitle('All commands') 17 | .setDescription(`[Web Dashboard](${(require('../../website/settings.json')).website.domain}/dashboard)`) 18 | .setFooter({ text: `Bot by ${eckigerluca.username}`, iconURL: eckigerluca_avatar }); 19 | 20 | embed.addFields( 21 | { name: '❓ Help', value: '`/help` `/support`' }, 22 | { name: '🔨 Moderation', value: '`/ban` `/kick` `/unban` `/clear` `/serverstats`' }, 23 | { name: '🏠 Community Management', value: '`/welcome setup` `/welcome enable` `/welcome disable` `/birthday setup` `/birthday enable` `/birthday disable`' }, 24 | { name: '🖼️ Media', value: '`/cat` `/fox` `/dog` `/raccoon` `/avatar` `/waifu` `/neko`' }, 25 | { name: '👤 Profiles', value: '`/profile view` `/profile edit` `/marry` `/divorce`' }, 26 | { name: '📸 Image Generation', value: '`/lolilicense`' }, 27 | { name: '🤣 Memes', value: '`/meme` `/meme help` `/adidas` `/magik`' }, 28 | { name: '🎭 Roleplay', value: '`/baka` `/bite` `/blush` `/bored` `/cry` `/cuddle` `/dance` `/facepalm` `/feed` `/happy` `/highfive` `/hug` `/kiss` `/laugh` `/pat` `/poke` `/pout` `/shrug` `/slap` `/sleep` `/smile` `/smug` `/stare` `/think` `/tickle` `/wave` `/wink` ||`/fuck`||' }, 29 | { name: '🔰 Other', value: '`/ping` `/whois` `/invite bot` `/invite server` `/random number` `/botinfo` `/botvote`' }, 30 | ); 31 | 32 | if (interaction.channel.nsfw) { 33 | embed.addFields( 34 | { name: '🔞 NSFW', value: '`/hentai (subreddit)` `/hentai help` `/hentaiwaifu` `/hentaineko` `/hentaiblowjob`' }, 35 | { name: '🔞² Boorus', value: '`/safebooru (tags)` `/konachan (tags)` `/gelbooru (tags)` `/rule34 (tags)` `/lolibooru (tags)`' }, 36 | ); 37 | } else { 38 | embed.addFields( 39 | { name: 'Note:', value: "NSFW commands are only visible in designated channels." }, 40 | ); 41 | } 42 | 43 | // if (interaction.channel.nsfw) { 44 | // embed.addFields( 45 | // { name: '❓ Help', value: '`/help` `/support`' }, 46 | // { name: '🔨 Moderation', value: '`/ban` `/kick` `/unban` `/clear` `/serverstats`' }, 47 | // { name: '🏠 Community Management', value: '`/welcome setup` `/welcome enable` `/welcome disable` `/birthday setup` `/birthday enable` `/birthday disable`' }, 48 | // { name: '🖼️ Media', value: '`/cat` `/fox` `/dog` `/raccoon` `/avatar` `/waifu` `/neko`' }, 49 | // { name: '👤 Profiles', value: '`/profile view` `/profile edit` `/marry` `/divorce`' }, 50 | // { name: '📸 Image Generation', value: '`/lolilicense`' }, 51 | // { name: '🤣 Memes', value: '`/meme` `/meme help` `/adidas`' }, 52 | // { name: '😂 Meme Generation', value: '`/magik (@member)`' }, 53 | // { name: '🎭 Roleplay', value: '`/baka` `/bite` `/blush` `/bored` `/cry` `/cuddle` `/dance` `/facepalm` `/feed` `/happy` `/highfive` `/hug` `/kiss` `/laugh` `/pat` `/poke` `/pout` `/shrug` `/slap` `/sleep` `/smile` `/smug` `/stare` `/think` `/tickle` `/wave` `/wink` `/fuck`' }, 54 | // { name: '🔰 Other', value: '`/ping` `/whois` `/invite bot` `/invite server` `/random number` `/botinfo` `/botvote`' }, 55 | // { name: '🔞 NSFW', value: '`/hentai (subreddit)` `/hentai help` `/hentaiwaifu` `/hentaineko` `/hentaiblowjob`' }, 56 | // { name: '🔞² Boorus', value: '`/safebooru (tags)` `/konachan (tags)` `/gelbooru (tags)` `/rule34 (tags)` `/lolibooru (tags)`' }, 57 | // ); 58 | // } 59 | // else { 60 | // embed.addFields( 61 | // { name: '❓ Help', value: '`/help` `/support`' }, 62 | // { name: '🔨 Moderation', value: '`/ban` `/kick` `/unban` `/clear` `/serverstats`' }, 63 | // { name: '👋 Welcome', value: '`/welcome setup` `/welcome enable` `/welcome disable`' }, 64 | // { name: '🖼️ Media', value: '`/cat` `/fox` `/dog` `/raccoon` `/avatar` `/waifu` `/neko`' }, 65 | // { name: '👤 Profiles', value: '`/profile view` `/profile edit` `/marry` `/divorce`' }, 66 | // { name: '📸 Image Generation', value: '`/lolilicense`' }, 67 | // { name: '🤣 Memes', value: '`/meme` `/meme help` `/adidas`' }, 68 | // { name: '😂 Meme Generation', value: '`/magik (@member)`' }, 69 | // { name: '🎭 Roleplay', value: '`/baka` `/bite` `/blush` `/bored` `/cry` `/cuddle` `/dance` `/facepalm` `/feed` `/happy` `/highfive` `/hug` `/kiss` `/laugh` `/pat` `/poke` `/pout` `/shrug` `/slap` `/sleep` `/smile` `/smug` `/stare` `/think` `/tickle` `/wave` `/wink` ||`/fuck`||' }, 70 | // { name: '🔰 Other', value: '`/ping` `/whois` `/invite bot` `/invite server` `/random number` `/botinfo` `/botvote`' }, 71 | // { name: '🔞 NSFW', value: '||`/hentai (subreddit)` `/hentai help` `/hentaiwaifu` `/hentaineko` `/hentaiblowjob`||' }, 72 | // { name: '🔞² Boorus', value: '||`/safebooru (tags)` `/konachan (tags)` `/gelbooru (tags)` `/rule34 (tags)` `/lolibooru (tags)`||' }, 73 | // ); 74 | // } 75 | await interaction.reply({ embeds: [embed] }); 76 | }, 77 | }; 78 | -------------------------------------------------------------------------------- /src/commands/meme/meme.js: -------------------------------------------------------------------------------- 1 | const { SlashCommandBuilder } = require('@discordjs/builders'); 2 | const { color } = require('../../data/config.json'); 3 | const { EmbedBuilder } = require('discord.js'); 4 | const fetch = require('node-fetch'); 5 | 6 | const REDDIT_ENABLED_MEME_SUBREDDITS = [ 7 | 'AdviceAnimals', 8 | 'Animemes', 9 | 'animememes', 10 | 'ComedyCemetery', 11 | 'dankmemes', 12 | 'funny', 13 | 'me_irl', 14 | 'MemeEconomy', 15 | 'memes', 16 | 'PrequelMemes', 17 | 'terriblefacebookmemes', 18 | 'wholesomememes', 19 | ]; 20 | 21 | module.exports = { 22 | data: new SlashCommandBuilder() 23 | .setName('meme') 24 | .setDescription('returns a random meme from reddit!') 25 | .addStringOption(option => 26 | option.setName('input') 27 | .setDescription('Put in `help` or the name of a subreddit here that is in the list') 28 | .setRequired(false)) 29 | .setDMPermission(false), 30 | 31 | async execute(interaction) { 32 | const embed = new EmbedBuilder() 33 | .setColor(color); 34 | 35 | const input = interaction.options.getString('input'); 36 | 37 | if (input == 'help') { 38 | embed.setTitle('List of subreddits') 39 | .addFields({ name: '»» 1-12 ««', value: REDDIT_ENABLED_MEME_SUBREDDITS.join('\n') }) 40 | .setFooter({ text: 'Page 1/1' }); 41 | await interaction.reply({ embeds: [embed] }); 42 | return; 43 | 44 | } 45 | else if (input !== null) { 46 | if (REDDIT_ENABLED_MEME_SUBREDDITS.map(list => list.toLowerCase()).indexOf(input.toLowerCase()) === -1) { 47 | const subreddit = REDDIT_ENABLED_MEME_SUBREDDITS[Math.floor(Math.random() * REDDIT_ENABLED_MEME_SUBREDDITS.length)]; 48 | const response = await fetch(`https://reddit.com/r/${subreddit}/random.json`); 49 | const data = await response.json(); 50 | 51 | const permalink = data[0].data.children[0].data.permalink; 52 | const memeUrl = `https://reddit.com${permalink}`; 53 | const memeImg = data[0].data.children[0].data.url; 54 | const memeTitle = data[0].data.children[0].data.title; 55 | const memeUpvotes = data[0].data.children[0].data.ups; 56 | const memeDownvotes = data[0].data.children[0].data.downs; 57 | const memeNumComents = data[0].data.children[0].data.num_comments; 58 | const subredditUrl = `https://reddit.com/r/${data[0].data.children[0].data.subreddit}`; 59 | 60 | embed.setTitle(memeTitle) 61 | .setDescription(`From [r/${subreddit}](${subredditUrl})`) 62 | .setURL(memeUrl) 63 | .setImage(memeImg) 64 | .setFooter({ text: `👍 ${memeUpvotes} 👎 ${memeDownvotes} 💬 ${memeNumComents}` }); 65 | 66 | const infoEmbed = new EmbedBuilder() 67 | .setTitle('404 Not Found') 68 | .setDescription("Seems like, that you've tried to get something from a subreddit that is not in the list!\nThat's why I decided to throw random shit..\nAnyway, you can see all supported subreddits with `/meme help`") 69 | .setColor(color); 70 | 71 | await interaction.reply({ embeds: [embed] }); 72 | await interaction.followUp({ embeds: [infoEmbed], ephemeral: true }); 73 | 74 | interaction.commandData = { 75 | name: interaction.commandName, 76 | options: [interaction.options], 77 | other: [{ 78 | subreddit: subreddit, 79 | }], 80 | }; 81 | return; 82 | } 83 | else if (REDDIT_ENABLED_MEME_SUBREDDITS.map(list => list.toLowerCase()).includes(input.toLowerCase())) { 84 | const subreddit = input; 85 | const response = await fetch(`https://reddit.com/r/${input}/random.json`); 86 | const data = await response.json(); 87 | 88 | const permalink = data[0].data.children[0].data.permalink; 89 | const memeUrl = `https://reddit.com${permalink}`; 90 | const memeImg = data[0].data.children[0].data.url; 91 | const memeTitle = data[0].data.children[0].data.title; 92 | const memeUpvotes = data[0].data.children[0].data.ups; 93 | const memeDownvotes = data[0].data.children[0].data.downs; 94 | const memeNumComents = data[0].data.children[0].data.num_comments; 95 | const subredditUrl = `https://reddit.com/r/${data[0].data.children[0].data.subreddit}`; 96 | 97 | embed.setTitle(memeTitle) 98 | .setDescription(`From [r/${subreddit}](${subredditUrl})`) 99 | .setURL(memeUrl) 100 | .setImage(memeImg) 101 | .setFooter({ text: `👍 ${memeUpvotes} 👎 ${memeDownvotes} 💬 ${memeNumComents}` }); 102 | 103 | await interaction.reply({ embeds: [embed] }); 104 | 105 | interaction.commandData = { 106 | name: interaction.commandName, 107 | options: [interaction.options], 108 | other: [{ 109 | subreddit: subreddit, 110 | }], 111 | }; 112 | return; 113 | } 114 | 115 | } 116 | else { 117 | const subreddit = REDDIT_ENABLED_MEME_SUBREDDITS[Math.floor(Math.random() * REDDIT_ENABLED_MEME_SUBREDDITS.length)]; 118 | const response = await fetch(`https://reddit.com/r/${subreddit}/random.json`); 119 | const data = await response.json(); 120 | 121 | const permalink = data[0].data.children[0].data.permalink; 122 | const memeUrl = `https://reddit.com${permalink}`; 123 | const memeImg = data[0].data.children[0].data.url; 124 | const memeTitle = data[0].data.children[0].data.title; 125 | const memeUpvotes = data[0].data.children[0].data.ups; 126 | const memeDownvotes = data[0].data.children[0].data.downs; 127 | const memeNumComents = data[0].data.children[0].data.num_comments; 128 | const subredditUrl = `https://reddit.com/r/${data[0].data.children[0].data.subreddit}`; 129 | 130 | embed.setTitle(memeTitle) 131 | .setDescription(`From [r/${subreddit}](${subredditUrl})`) 132 | .setURL(memeUrl) 133 | .setImage(memeImg) 134 | .setFooter({ text: `👍 ${memeUpvotes} 👎 ${memeDownvotes} 💬 ${memeNumComents}` }); 135 | 136 | await interaction.reply({ embeds: [embed] }); 137 | 138 | interaction.commandData = { 139 | name: interaction.commandName, 140 | options: [interaction.options], 141 | other: [{ 142 | subreddit: subreddit, 143 | }], 144 | }; 145 | return; 146 | } 147 | }, 148 | }; 149 | -------------------------------------------------------------------------------- /src/commands/community-management/birthday.js: -------------------------------------------------------------------------------- 1 | const { color } = require('../../data/config.json'); 2 | const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, Colors, ChannelType, ModalBuilder, ActionRowBuilder, TextInputBuilder, TextInputStyle } = require('discord.js'); 3 | 4 | module.exports = { 5 | data: new SlashCommandBuilder() 6 | .setName("birthday") 7 | .setDescription("Birthday Function Commands") 8 | .addSubcommand(subcommand => 9 | subcommand 10 | .setName("setup") 11 | .setDescription("Set up the birthday function for your server") 12 | .addChannelOption(option => 13 | option 14 | .setName("channel") 15 | .setDescription("The channel where the birthday messages will be sent to") 16 | .addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement) 17 | .setRequired(true)) 18 | .addStringOption(option => 19 | option 20 | .setName("message") 21 | .setDescription("Choose yes if wou'd like to use a custom message sent to the specifed channel") 22 | .setRequired(true) 23 | .addChoices( 24 | { name: "Yes", value: "yes" }, 25 | { name: "No", value: "no" }, 26 | ))) 27 | .addSubcommand(subcommand => 28 | subcommand 29 | .setName("enable") 30 | .setDescription("Enable the birthday function on your server")) 31 | .addSubcommand(subcommand => 32 | subcommand 33 | .setName("disable") 34 | .setDescription("Disable the birthday function on your server")) 35 | .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) 36 | .setDMPermission(false), 37 | 38 | async execute(interaction) { 39 | const dbClient = interaction.client.dbClient; 40 | const serverCollection = await dbClient.db("darling").collection("servers"); 41 | let server = await serverCollection.findOne({ _id: interaction.guild.id }); 42 | if (!server) { 43 | const document = { 44 | _id: interaction.guild.id, 45 | birthday: { 46 | enabled: false, 47 | channel: null, 48 | customMessage: { 49 | enabled: false, 50 | message: null, 51 | }, 52 | }, 53 | }; 54 | await serverCollection.insertOne(document); 55 | server = await serverCollection.findOne({ _id: interaction.guild.id }); 56 | } 57 | 58 | if (!server.birthday) { 59 | const updateDocument = { 60 | $set: { 61 | birthday: { 62 | enabled: false, 63 | channel: null, 64 | customMessage: { 65 | enabled: false, 66 | message: null, 67 | }, 68 | }, 69 | }, 70 | }; 71 | await serverCollection.updateOne({ _id: interaction.guild.id }, updateDocument); 72 | server = await serverCollection.findOne({ _id: interaction.guild.id }); 73 | } 74 | 75 | if (interaction.options.getSubcommand() === "setup") { 76 | // setup 77 | const channel = interaction.options.getChannel("channel"); 78 | const message = interaction.options.getString("message"); 79 | const customMessage = { 80 | enabled: false, 81 | message: null, 82 | }; 83 | if (message === "yes") { 84 | const modal = new ModalBuilder() 85 | .setTitle("Custom Birthday Message") 86 | .setCustomId("customBirthdayMessage"); 87 | 88 | const customBirthdayMessageInput = new TextInputBuilder() 89 | .setCustomId('customBirthdayMessage') 90 | .setLabel('Custom Birthday Message') 91 | .setStyle(TextInputStyle.Paragraph) 92 | .setValue(server.birthday.customMessage.message ? server.birthday.customMessage.message : '') 93 | .setPlaceholder('custom birthday message o.o\n${memberName} displays their name and ${memberMention} mentions them!') 94 | .setMaxLength(4000) 95 | .setRequired(true); 96 | 97 | const customBirthdayMessageActionRow = new ActionRowBuilder() 98 | .addComponents(customBirthdayMessageInput); 99 | 100 | modal.addComponents(customBirthdayMessageActionRow); 101 | await interaction.showModal(modal); 102 | 103 | const filter = (newInteraction) => newInteraction.customId === 'customBirthdayMessage'; 104 | interaction.awaitModalSubmit({ filter, time: 300_000 }) 105 | .then(async newInteraction => { 106 | const inputCustomBirthdayMessage = newInteraction.fields.getTextInputValue('customBirthdayMessage'); 107 | 108 | customMessage.enabled = true; 109 | customMessage.message = inputCustomBirthdayMessage; 110 | 111 | const updateDocument = { 112 | $set: { 113 | "birthday.enabled": true, 114 | "birthday.channel": channel.id, 115 | "birthday.customMessage.enabled": customMessage.enabled, 116 | "birthday.customMessage.message": customMessage.message, 117 | }, 118 | }; 119 | 120 | await serverCollection.updateOne({ _id: interaction.guild.id }, updateDocument); 121 | const embed = new EmbedBuilder() 122 | .setColor(Colors.Green) 123 | .setDescription("The birthday function has been set up!\n\n**Channel:** <#" + channel.id + "\n**Custom Message:** " + (customMessage.enabled ? "Yes" : "No") + "\n\n**Note:** If you would like to change any of these settings, you can do so by running the `/birthday setup` command again!\nYou can disable it by running `/birthday disable`!") 124 | .addFields( 125 | { name: "Custom Message", value: `\`\`\`${inputCustomBirthdayMessage}\`\`\`` }, 126 | ); 127 | return await newInteraction.reply({ embeds: [embed], ephemeral: true }); 128 | }) 129 | .catch(async err => { 130 | return await interaction.followUp({ content: 'You took too long to respond!', ephemeral: true }); 131 | }); 132 | } else if (message === "no") { 133 | customMessage.enabled = false; 134 | customMessage.message = null; 135 | 136 | const updateDocument = { 137 | $set: { 138 | "birthday.enabled": true, 139 | "birthday.channel": channel.id, 140 | "birthday.customMessage.enabled": customMessage.enabled, 141 | "birthday.customMessage.message": customMessage.message, 142 | }, 143 | }; 144 | await serverCollection.updateOne({ _id: interaction.guild.id }, updateDocument); 145 | const embed = new EmbedBuilder() 146 | .setColor(Colors.Green) 147 | .setDescription("The birthday function has been set up!\n\n**Channel:** <#" + channel.id + "\n**Custom Message:** " + (customMessage.enabled ? "Yes" : "No") + "\n\n**Note:** If you would like to change any of these settings, you can do so by running the `/birthday setup` command again!\nYou can disable it by running `/birthday disable`!"); 148 | return interaction.reply({ embeds: [embed], ephemeral: true }); 149 | } 150 | } 151 | 152 | if (interaction.options.getSubcommand() === "enable") { 153 | if (server.birthday.enabled) { 154 | const embed = new EmbedBuilder() 155 | .setColor(Colors.Red) 156 | .setDescription("The birthday function is already enabled!"); 157 | return interaction.reply({ embeds: [embed], ephemeral: true }); 158 | } else { 159 | const updateDocument = { 160 | $set: { 161 | "birthday.enabled": true, 162 | }, 163 | }; 164 | await serverCollection.updateOne({ _id: interaction.guild.id }, updateDocument); 165 | const embed = new EmbedBuilder() 166 | .setColor(Colors.Green) 167 | .setDescription("The birthday function has been enabled!"); 168 | return interaction.reply({ embeds: [embed], ephemeral: true }); 169 | } 170 | } 171 | 172 | if (interaction.options.getSubcommand() === "disable") { 173 | if (!server.birthday.enabled) { 174 | const embed = new EmbedBuilder() 175 | .setColor(Colors.Red) 176 | .setDescription("The birthday function is already disabled!"); 177 | return interaction.reply({ embeds: [embed], ephemeral: true }); 178 | } else { 179 | const updateDocument = { 180 | $set: { 181 | "birthday.enabled": false, 182 | }, 183 | }; 184 | await serverCollection.updateOne({ _id: interaction.guild.id }, updateDocument); 185 | const embed = new EmbedBuilder() 186 | .setColor(Colors.Green) 187 | .setDescription("The birthday function has been disabled!"); 188 | return interaction.reply({ embeds: [embed], ephemeral: true }); 189 | } 190 | } 191 | }, 192 | }; 193 | -------------------------------------------------------------------------------- /src/commands/profile/profile.js: -------------------------------------------------------------------------------- 1 | const { color } = require('../../data/config.json'); 2 | const { EmbedBuilder, SlashCommandBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } = require('discord.js'); 3 | 4 | module.exports = { 5 | data: new SlashCommandBuilder() 6 | .setName("profile") 7 | .setDescription("View your/others profile and edit it") 8 | .addSubcommand(subcommand => 9 | subcommand.setName("view") 10 | .setDescription("View your/others profile") 11 | .addUserOption(option => option.setName("target").setDescription("Select user to show the profile of (leave empty for your's)"))) 12 | .addSubcommand(subcommand => 13 | subcommand.setName("edit") 14 | .setDescription("Edit your profile")) 15 | .setDMPermission(false), 16 | 17 | async execute(interaction) { 18 | const dbClient = interaction.client.dbClient; 19 | const db = dbClient.db("darling"); 20 | const userCollection = db.collection("users"); 21 | if (interaction.options.getSubcommand() == "view") { 22 | await interaction.deferReply({ content: "Generating Profile. Please wait..." }); 23 | 24 | let target = interaction.options.getUser("target") ?? interaction.member; 25 | if (target != interaction.member) { 26 | try { 27 | target = await interaction.guild.members.fetch(target); 28 | } catch { 29 | await interaction.editReply({ content: "Could not get the user that you specified. Please try again.", ephemeral: true }); 30 | } 31 | } 32 | if (target.user.bot && target.user != interaction.client.user) return await interaction.editReply({ content: "You can't view the profile of a bot.", ephemeral: true }); 33 | let findResult = await userCollection.findOne({ 34 | "_id": target.id, 35 | }); 36 | 37 | if (!findResult) { 38 | const document = { 39 | "_id": target.id, 40 | "gender": "Not set...", 41 | "pronouns": "Not set...", 42 | "birthday": "00/00", 43 | "botMemberSince": `${Math.floor(Date.now() / 1000)}`, 44 | "money": 1000, 45 | "description": "Not set...", 46 | "color": color, 47 | "style": 0, 48 | "background": 0, 49 | "married": { 50 | "status": false, 51 | "partner": null, 52 | "date": null, 53 | }, 54 | "premium": false, 55 | "inventory": {}, 56 | }; 57 | await userCollection.insertOne(document); 58 | findResult = await userCollection.findOne({ 59 | "_id": target.id, 60 | }); 61 | } 62 | 63 | // style 0 = embed 64 | if (findResult.style == 0) { 65 | 66 | const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; 67 | const rawBirthday = (findResult.birthday).split("/"); 68 | let birthday = `${rawBirthday[0]}. ${months[rawBirthday[1] - 1]}`; 69 | if (rawBirthday[0] == "00" && rawBirthday[1] == "00") birthday = "Not set..."; 70 | 71 | let profileDescription = `**» Name:** ${target.nickname ?? target.user.username}\n**» Gender:** ${findResult.gender}\n**» Pronouns:** ${findResult.pronouns}\n**» Birthday:** ${birthday}\n**» Bot Member Since:** \n**» Money:** ${findResult.money} ${String.fromCodePoint(0x1FA99)}`; 72 | 73 | if (findResult.married.status) { 74 | profileDescription += `\n**» Married to:** ${await interaction.client.users.fetch(findResult.married.partner)}`; 75 | } 76 | 77 | const embed = new EmbedBuilder() 78 | .setColor(findResult.color) 79 | .setThumbnail(target.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false })) 80 | .setAuthor({ name: `Profile of ${target.user.username}`, iconURL: target.displayAvatarURL({ size: 1024, extension: 'png', forceStatic: false }) }) 81 | .setFooter({ text: 'Edit your profile with /profile edit' }) 82 | .setDescription(profileDescription); 83 | embed.addFields({ name: "» Description:", value: findResult.description }); 84 | await interaction.editReply({ embeds: [embed] }); 85 | } 86 | 87 | } else if (interaction.options.getSubcommand() == "edit") { 88 | const target = interaction.member; 89 | let findResult = await userCollection.findOne({ 90 | "_id": target.id, 91 | }); 92 | 93 | if (!findResult) { 94 | const document = { 95 | "_id": target.id, 96 | "gender": "Not set...", 97 | "pronouns": "Not set...", 98 | "birthday": "00/00", 99 | "botMemberSince": `${Math.floor(Date.now() / 1000)}`, 100 | "money": 1000, 101 | "description": "Not set...", 102 | "color": color, 103 | "style": 0, 104 | "background": 0, 105 | "married": { 106 | "status": false, 107 | "partner": null, 108 | "date": null, 109 | }, 110 | "premium": false, 111 | "inventory": {}, 112 | }; 113 | await userCollection.insertOne(document); 114 | findResult = await userCollection.findOne({ 115 | "_id": target.id, 116 | }); 117 | } 118 | 119 | const modal = new ModalBuilder() 120 | .setCustomId('profileEdit') 121 | .setTitle('Edit your Profile'); 122 | 123 | const genderInput = new TextInputBuilder() 124 | .setCustomId('gender') 125 | .setLabel('What is your gender?') 126 | .setStyle(TextInputStyle.Short) 127 | .setValue(findResult.gender) 128 | .setPlaceholder('e.g. Male') 129 | .setRequired(true); 130 | 131 | const pronounsInput = new TextInputBuilder() 132 | .setCustomId('pronouns') 133 | .setLabel('What are your pronouns?') 134 | .setStyle(TextInputStyle.Short) 135 | .setValue(findResult.pronouns) 136 | .setPlaceholder('e.g. He/Him') 137 | .setRequired(true); 138 | 139 | const birthdayInput = new TextInputBuilder() 140 | .setCustomId('birthday') 141 | .setLabel('What is your birthday? (Format: DD/MM)') 142 | .setStyle(TextInputStyle.Short) 143 | .setValue(findResult.birthday) 144 | .setPlaceholder('e.g. 16/12') 145 | .setMinLength(5) 146 | .setMaxLength(5) 147 | .setRequired(true); 148 | 149 | const colorInput = new TextInputBuilder() 150 | .setCustomId('color') 151 | .setLabel('Set the accent of your profile (Hex Code)') 152 | .setStyle(TextInputStyle.Short) 153 | .setValue(findResult.color) 154 | .setPlaceholder('e.g. #FF0000') 155 | .setMinLength(7) 156 | .setMaxLength(7) 157 | .setRequired(true); 158 | 159 | const descriptionInput = new TextInputBuilder() 160 | .setCustomId('description') 161 | .setLabel('Set a description for your profile') 162 | .setStyle(TextInputStyle.Paragraph) 163 | .setValue(findResult.description) 164 | .setPlaceholder('e.g. I am a cool person') 165 | .setMaxLength(100) 166 | .setRequired(true); 167 | 168 | const genderActionRow = new ActionRowBuilder().addComponents(genderInput); 169 | const pronounsActionRow = new ActionRowBuilder().addComponents(pronounsInput); 170 | const birthdayActionRow = new ActionRowBuilder().addComponents(birthdayInput); 171 | const colorActionRow = new ActionRowBuilder().addComponents(colorInput); 172 | const descriptionActionRow = new ActionRowBuilder().addComponents(descriptionInput); 173 | 174 | modal.addComponents(genderActionRow, pronounsActionRow, birthdayActionRow, colorActionRow, descriptionActionRow); 175 | 176 | await interaction.showModal(modal); 177 | 178 | const filter = (newInteraction) => newInteraction.customId === 'profileEdit'; 179 | interaction.awaitModalSubmit({ filter, time: 300_000 }) 180 | .then(async newInteraction => { 181 | const rawBirthday = (newInteraction.fields.getTextInputValue('birthday')).split('/'); 182 | let birthday = `${rawBirthday[0]}/${rawBirthday[1]}`; 183 | if (rawBirthday[0] > 31 || rawBirthday[1] > 12) birthday = "00/00"; 184 | if (birthday.includes(undefined)) birthday = "00/00"; 185 | const updateDocument = { 186 | $set: { 187 | "gender": newInteraction.fields.getTextInputValue('gender'), 188 | "pronouns": newInteraction.fields.getTextInputValue('pronouns'), 189 | "birthday": birthday, 190 | "color": newInteraction.fields.getTextInputValue('color'), 191 | "description": newInteraction.fields.getTextInputValue('description'), 192 | }, 193 | }; 194 | await userCollection.updateOne(findResult, updateDocument); 195 | await newInteraction.reply({ content: 'Your profile has been updated!', ephemeral: true }); 196 | }) 197 | .catch(async err => await interaction.followUp({ content: 'You took too long to respond!', ephemeral: true })); 198 | } 199 | }, 200 | }; 201 | -------------------------------------------------------------------------------- /src/commands/profile/marry.js: -------------------------------------------------------------------------------- 1 | const { color } = require('../../data/config.json'); 2 | const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); 3 | 4 | function sleep(ms) { 5 | return new Promise(resolve => setTimeout(resolve, ms)); 6 | } 7 | 8 | module.exports = { 9 | data: new SlashCommandBuilder() 10 | .setName("marry") 11 | .setDescription("Marry someone!") 12 | .addUserOption(option => option.setName("target").setDescription("Select user to marry").setRequired(true)) 13 | .setDMPermission(false), 14 | 15 | async execute(interaction) { 16 | await interaction.deferReply({ ephemeral: true }); 17 | 18 | const target = interaction.options.getUser("target"); 19 | const eckigerluca = await interaction.client.users.fetch('173374602389618688'); 20 | const dbClient = interaction.client.dbClient; 21 | const db = dbClient.db("darling"); 22 | const userCollection = db.collection("users"); 23 | if (target == interaction.client.user) return await interaction.editReply({ content: "You can't marry me!", ephemeral: true }); 24 | if (target == eckigerluca) return await interaction.editReply({ content: "Are you trying to steal my man?!", ephemeral: true }); 25 | if (target.bot) return await interaction.editReply({ content: "You can't marry a bot!", ephemeral: true }); 26 | if (target == interaction.member.user) return await interaction.editReply({ content: "You can't marry yourself.", ephemeral: true }); 27 | 28 | const userResult = await userCollection.findOne({ "_id": interaction.member.id }); 29 | if (!userResult) return await interaction.editReply({ content: "You dont't even own a profile! Set it up with `/profile edit` first!", ephemeral: true }); 30 | if (Object.values(userResult).includes("Not set...") || Object.values(userResult).includes("00/00")) return await interaction.editReply({ content: "Set up your profile first with `/profile edit`!", ephemeral: true }); 31 | if (userResult.married.status) return await interaction.editReply({ content: `You are already married to <@${userResult.married.partner}>!`, ephemeral: true }); 32 | 33 | const targetResult = await userCollection.findOne({ "_id": target.id }); 34 | if (!targetResult) return await interaction.editReply({ content: `${target} doesn't even own a profile! Tell them to set it up with \`/profile edit\`!`, ephemeral: true }); 35 | if (Object.values(targetResult).includes("Not set...") || Object.values(targetResult).includes("00/00")) return await interaction.editReply({ content: `${target} needs to set their profile up first with \`/profile edit\`!`, ephemeral: true }); 36 | if (targetResult.married.status) return await interaction.editReply({ content: `${target} is already married!`, ephemeral: true }); 37 | 38 | const userConfirmEmbed = new EmbedBuilder() 39 | .setTitle("Proposal Confirmation") 40 | .setDescription(`Are you sure you want to marry ${target}?\nClick on one of the buttons below to confirm. Starting now, you have 30 seconds to decide.`) 41 | .setThumbnail(target.displayAvatarURL({ forceStatic: false })) 42 | .setColor(color) 43 | .setTimestamp(); 44 | 45 | const userRow = new ActionRowBuilder() 46 | .addComponents( 47 | new ButtonBuilder() 48 | .setCustomId("marry_confirm_user") 49 | .setEmoji("1061678465914507386") 50 | .setStyle(ButtonStyle.Success), 51 | new ButtonBuilder() 52 | .setCustomId("marry_cancel_user") 53 | .setEmoji("1061678468380774440") 54 | .setStyle(ButtonStyle.Danger), 55 | ); 56 | 57 | await interaction.editReply({ embeds: [userConfirmEmbed], components: [userRow], ephemeral: true }); 58 | 59 | let userActed = false; 60 | let functionRan = false; 61 | interaction.client.once("interactionCreate", async (newUserInteraction) => { 62 | if (functionRan) return; 63 | functionRan = true; 64 | if (!newUserInteraction.isButton()) return; 65 | if (newUserInteraction.user.id != interaction.member.user.id) return; 66 | if (newUserInteraction.customId == "marry_confirm_user") { 67 | userActed = true; 68 | await interaction.editReply({ content: `Proposal sent to ${target} !`, embeds: [], components: [], ephemeral: true }); 69 | 70 | const targetRow = new ActionRowBuilder() 71 | .addComponents( 72 | new ButtonBuilder() 73 | .setCustomId("marry_confirm_target") 74 | .setEmoji("1061678465914507386") 75 | .setStyle(ButtonStyle.Success), 76 | new ButtonBuilder() 77 | .setCustomId("marry_cancel_target") 78 | .setEmoji("1061678468380774440") 79 | .setStyle(ButtonStyle.Danger), 80 | ); 81 | 82 | const targetConfirmEmbed = new EmbedBuilder() 83 | .setTitle("Someone wants to marry you!") 84 | .setDescription(`${interaction.member.user} wants to marry you! Starting now, you have 10 minutes to decide wheter you want to accept or decline the proposal.`) 85 | .setColor(color) 86 | .setTimestamp(); 87 | 88 | let targetMessage; 89 | try { 90 | targetMessage = await target.send({ embeds: [targetConfirmEmbed], components: [targetRow] }); 91 | } 92 | catch { 93 | return await interaction.editReply({ content: `Couldn't DM ${target}!\nPlease tell them to allow DMs from server members in their \`Privacy & Safety\` settings.\n\nThe proposal has been cancelled.`, embeds: [], components: [], ephemeral: true }); 94 | } 95 | 96 | let targetActed = false; 97 | interaction.client.once("interactionCreate", async (newTargetInteraction) => { 98 | if (!newTargetInteraction.isButton()) return; 99 | if (newTargetInteraction.user.id != target.id) return; 100 | if (newTargetInteraction.customId == "marry_confirm_target") { 101 | targetActed = true; 102 | const curDate = Math.floor(Date.now() / 1000); 103 | const userUpdateDocument = { 104 | $set: { 105 | "married": { 106 | status: true, 107 | partner: target.id, 108 | date: curDate, 109 | }, 110 | }, 111 | }; 112 | const targetUpdateDocument = { 113 | $set: { 114 | "married": { 115 | status: true, 116 | partner: interaction.member.user.id, 117 | date: curDate, 118 | }, 119 | }, 120 | }; 121 | 122 | await userCollection.updateOne(userResult, userUpdateDocument); 123 | await userCollection.updateOne(targetResult, targetUpdateDocument); 124 | 125 | const targetSuccessEmbed = new EmbedBuilder() 126 | .setTitle("Proposal Accepted") 127 | .setDescription(`You have accepted the proposal from ${interaction.member.user}! Congratulations!`) 128 | .setColor(color) 129 | .setTimestamp(); 130 | 131 | await targetMessage.edit({ embeds: [targetSuccessEmbed], components: [] }); 132 | 133 | const userSuccessEmbed = new EmbedBuilder() 134 | .setTitle("Proposal Accepted") 135 | .setDescription(`Your proposal to ${target} has been accepted! Congratulations!`) 136 | .setColor(color) 137 | .setTimestamp(); 138 | 139 | try { 140 | return await interaction.member.user.send({ embeds: [userSuccessEmbed] }); 141 | } 142 | catch { 143 | return await interaction.followUp({ content: `${interaction.member.user}\nCouldn't DM you!\nPlease allow DMs from server members in your \`Privacy & Safety\` settings!\n\nYour proposal to ${target} has been accepted! Congratulations!`, ephemeral: true }); 144 | } 145 | 146 | } else if (newTargetInteraction.customId == "marry_cancel_target") { 147 | targetActed = true; 148 | const targetFailEmbed = new EmbedBuilder() 149 | .setTitle("Proposal Declined") 150 | .setDescription(`You have declined the proposal from ${interaction.member.user}!`) 151 | .setColor(color) 152 | .setTimestamp(); 153 | 154 | await targetMessage.edit({ embeds: [targetFailEmbed], components: [] }); 155 | try { 156 | return await interaction.member.user.send({ content: `Your proposal to ${target} has been declined!` }); 157 | } catch { 158 | return await interaction.followUp({ content: `${interaction.member.user}\nCouldn't DM you!\nPlease allow DMs from server members in your \`Privacy & Safety\` settings!\n\nYour proposal to ${target} has been declined!`, ephemeral: true }); 159 | } 160 | } 161 | }); 162 | 163 | await sleep(600_000); 164 | if (targetActed) return; 165 | await targetMessage.edit({ content: `You took too long to decide if you want to marry ${interaction.member}!`, embeds: [], components: [] }); 166 | try { 167 | return await interaction.member.user.send({ content: `Your proposal to ${target} has been cancelled because they took too long to decide!` }); 168 | } 169 | catch { 170 | return await interaction.followUp({ content: `${interaction.member.user}\nCouldn't DM you!\nPlease allow DMs from server members in your \`Privacy & Safety\` settings!\n\nYour proposal to ${target} has been cancelled because they took too long to decide!`, ephemeral: true }); 171 | } 172 | } 173 | else if (newUserInteraction.customId == "marry_cancel_user") { 174 | userActed = true; 175 | const userCancelEmbed = new EmbedBuilder() 176 | .setTitle("Proposal Cancelled") 177 | .setDescription(`You have cancelled the proposal to ${target}.`) 178 | .setColor(color) 179 | .setTimestamp(); 180 | return await interaction.editReply({ embeds: [userCancelEmbed], components: [], ephemeral: true }); 181 | } 182 | }); 183 | 184 | await sleep(30_000); 185 | if (userActed) return; 186 | const userTimeoutEmbed = new EmbedBuilder() 187 | .setTitle("Proposal Cancelled") 188 | .setDescription(`You have not confirmed the proposal to ${target} in time.`) 189 | .setColor(color) 190 | .setTimestamp(); 191 | 192 | return await interaction.editReply({ embeds: [userTimeoutEmbed], components: [], ephemeral: true }); 193 | }, 194 | }; 195 | -------------------------------------------------------------------------------- /src/website/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Darling. - Discord Bot 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Darling. | Home 35 | 88 | 89 | 95 | 96 | 97 | 98 | <%- await include('header.ejs'); %> 99 | 126 | 127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |

<%= servers %>

135 |

Servers

136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |

<%= (users / 1000).toFixed(1) %>K

145 |

Users

146 |
147 |
148 |
149 |
150 | 162 | 163 | 175 | 186 | 197 |
198 |
199 |
200 | 201 |
202 |
203 | 218 | 219 | 234 | 235 | 244 |
245 |
246 | 247 | 248 | <%- await include('footer.ejs'); %> 249 | <%- await include('secret.ejs'); %> 250 | <%- await include('error.ejs'); %> -------------------------------------------------------------------------------- /src/commands/nsfw/hentai.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-lonely-if */ 2 | /* eslint-disable no-inner-declarations */ 3 | const { SlashCommandBuilder } = require('@discordjs/builders'); 4 | const { color } = require('../../data/config.json'); 5 | const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); 6 | const fetch = require('node-fetch'); 7 | const logger = require('silly-logger'); 8 | 9 | function sleep(ms) { 10 | return new Promise(resolve => setTimeout(resolve, ms)); 11 | } 12 | 13 | const REDDIT_ENABLED_HENTAI_SUBREDDITS = [ 14 | "ahegao", 15 | "AmberHentai", 16 | "AnalHentai", 17 | "animearmpits", 18 | "animeassholes", 19 | "animebodysuits", 20 | "AnimeBooty", 21 | "AnimeFeets", 22 | "AnimeFootFetish", 23 | "animehandjobs", 24 | "AnimeHeelsAndBoots", 25 | "AnimeHighHeels", 26 | "animelegs", 27 | "animelegwear", 28 | "AnimeLingerie", 29 | "animemaids", 30 | "animemidriff", 31 | "AnimeMILFS", 32 | "animepantsu", 33 | "AnimePantyhose", 34 | "animepointyears", 35 | "AnimePussy", 36 | "AnimeSeeThrough", 37 | "animeshirtgaps", 38 | "AnimeStockings", 39 | "AnimeTitties", 40 | "AraAra", 41 | "Artistic_Hentai", 42 | "AshiToFutomomo", 43 | "AsunaHentai", 44 | "Atago", 45 | "AverageAnimeTiddies", 46 | "AyakaHentai", 47 | "AzurLaneXXX", 48 | "AzurLewd", 49 | "bakunyuu", 50 | "BarbaraNSFW", 51 | "BeachHentai", 52 | "BeidouNSFW", 53 | "BigAnimeTiddies", 54 | "BikiniMoe", 55 | "BimboHentai", 56 | "BlondeHairWaifu", 57 | "bluehairhentai", 58 | "bunnygirlhentai", 59 | "CedehsHentai", 60 | "ChurchofBooty", 61 | "ChurchOfRikka", 62 | "ConfidentHentai", 63 | "CultureImpact", 64 | "CumHentai", 65 | "cute_hentai", 66 | "DarlingInTheFranXXX", 67 | "deepthroathentai", 68 | "dekaihentai", 69 | "DoA_Rule34", 70 | "ecchi", 71 | "Elegant34", 72 | "ElfHentai", 73 | "EmbarrassedHentai", 74 | "EmiliaHentai", 75 | "EulaNSFW", 76 | "FateEcchi", 77 | "FateHentai", 78 | "Fateishtar", 79 | "FateXXX", 80 | "FGOcomics", 81 | "Fire_Emblem_R34", 82 | "Formidable_AZ", 83 | "FreeuseHentai", 84 | "funpiece", 85 | "GanyuNSFW", 86 | "GenshinImpactHentai", 87 | "GenshinImpactNSFW", 88 | "GenshinLewds", 89 | "glasshentai", 90 | "GloryHo", 91 | "grailwhores", 92 | "HardcoreHentaiBondage", 93 | "HelplessHentai", 94 | "Hen_Tai", 95 | "hentai", 96 | "hentai411", 97 | "Hentai_feet", 98 | "HentaiAnal", 99 | "HentaiAnaru", 100 | "HentaiBlessing", 101 | "hentaibondage", 102 | "HentaiBreeding", 103 | "Hentaibuttplug", 104 | "HentaiCameltoe", 105 | "hentaifemdom", 106 | "hentaigg", 107 | "Hentaiofthedead", 108 | "HentaiPetgirls", 109 | "HentaiPixxx", 110 | "HentaiSchoolGirls", 111 | "HentaiVTuberGirls", 112 | "hentaiwaifus69", 113 | "HentaiWorldInfo", 114 | "highschooldxdr34", 115 | "Hololewd", 116 | "HonkaiImpactRule34", 117 | "HuTaoNSFW", 118 | "ishtarhentai", 119 | "IWantToBeHerHentai", 120 | "Jeanne", 121 | "Joshi_Kosei", 122 | "kemonomimi", 123 | "KeqingNSFW", 124 | "KeyholeHentai", 125 | "Lewd_Not_Hentai", 126 | "LewdAnimeGirls", 127 | "LewdGenshinImpact", 128 | "LingerieHentai", 129 | "lowlegsheaven", 130 | "MaidHentai", 131 | "MamaRaikou", 132 | "MasturbationHentai", 133 | "MidriffHentai", 134 | "MikuNakanoNSFW", 135 | "milfhentai", 136 | "Mona_NSFW", 137 | "MonaNSFW", 138 | "MonsterGirl", 139 | "muchihentai", 140 | "nakanoitsuki", 141 | "Naruto_Hentai", 142 | "Nekomimi", 143 | "NinoNakanoNSFW", 144 | "NintendoWaifus", 145 | "NoneHumanMoe", 146 | "nsfw_zhentai", 147 | "NurseHentai", 148 | "officelady", 149 | "OfficialSenpaiHeat", 150 | "OniMaidTwins", 151 | "oppai_gif", 152 | "OppaiLove", 153 | "OriginalMoe", 154 | "overflowingoppai", 155 | "OverOppai", 156 | "oversizedbreasts", 157 | "Paizuri", 158 | "pantsu", 159 | "PublicHentai", 160 | "QuintupletsHentai", 161 | "RaidenMeiNSFW", 162 | "RaidenNSFW", 163 | "rape_hentai", 164 | "ReZeroHentai", 165 | "rippedanimelegwear", 166 | "RosariaNSFW", 167 | "rule34", 168 | "Rule34cumsluts", 169 | "rule34feet", 170 | "Rule34LoL", 171 | "RWBYNSFW", 172 | "Saber", 173 | "saohentai", 174 | "serafuku2D", 175 | "sex_comics", 176 | "SFMCompileClub", 177 | "SoakedHentai", 178 | "StuckHentai", 179 | "Sukebei", 180 | "Sweatymoe", 181 | "swimsuithentai", 182 | "Taihou", 183 | "Tentai", 184 | "ThiccElves", 185 | "thick_hentai", 186 | "thighdeology", 187 | "thighhighhentai", 188 | "tohsakahentai", 189 | "ToplessHentai", 190 | "uncensoredhentai", 191 | "Uniform_Hentai", 192 | "UpskirtHentai", 193 | "VaginaHentai", 194 | "VideoGame_Hentai", 195 | "VshojoLewds", 196 | "waifusgonewild", 197 | "WaifusOnCouch", 198 | "Waifutights", 199 | "WesternHentai", 200 | "XrayHentai", 201 | "YaeMikoNSFW", 202 | "ZeroTwoHentai", 203 | ]; 204 | 205 | module.exports = { 206 | data: new SlashCommandBuilder() 207 | .setName('hentai') 208 | .setDescription('returns random hentai from reddit') 209 | .addStringOption(option => 210 | option.setName('input') 211 | .setDescription('Put in `help` or the name of a subreddit here that is in the list') 212 | .setRequired(false)) 213 | .setDMPermission(false), 214 | 215 | async execute(interaction) { 216 | let row = new ActionRowBuilder() 217 | .addComponents( 218 | new ButtonBuilder() 219 | .setCustomId('hentai1') 220 | .setEmoji('1️⃣') 221 | .setStyle(ButtonStyle.Primary), 222 | new ButtonBuilder() 223 | .setCustomId('hentai2') 224 | .setEmoji('2️⃣') 225 | .setStyle(ButtonStyle.Primary), 226 | ); 227 | if (interaction.channel.nsfw) { 228 | 229 | const input = interaction.options.getString('input'); 230 | let subreddit = ''; 231 | let notfound; 232 | 233 | if (input == 'help') { 234 | const helpEmbed1 = new EmbedBuilder() 235 | .setTitle('List of subreddits | Page 1') 236 | .setColor(color) 237 | .addFields( 238 | { name: "» 1-25 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(0, 25).join('\n'), inline: true }, 239 | { name: '» 26-50 «', value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(25, 50).join('\n'), inline: true }, 240 | { name: "» 51-75 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(50, 75).join("\n"), inline: true }, 241 | { name: "» 76-100 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(75, 100).join('\n'), inline: true }, 242 | { name: "» 101-125 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(100, 125).join('\n'), inline: true }, 243 | { name: "» 126-150 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(125, 150).join('\n'), inline: true }, 244 | ) 245 | .setFooter({ text: "Large and lower case is not important, just make sure to spell them correctly!" }); 246 | const helpEmbed2 = new EmbedBuilder() 247 | .setTitle('List of subreddits | Page 2') 248 | .setColor(color) 249 | .addFields( 250 | { name: "» 151-175 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(150, 175).join('\n'), inline: true }, 251 | { name: "» 176-189 «", value: REDDIT_ENABLED_HENTAI_SUBREDDITS.slice(175, 189).join("\n"), inline: true }, 252 | ) 253 | .setFooter({ text: "Large and lower case is not important, just make sure to spell them correctly!" }); 254 | await interaction.reply({ embeds: [helpEmbed1], components: [row] }); 255 | interaction.client.on('interactionCreate', newInteraction => { 256 | if (!newInteraction.isButton()) return; 257 | if (newInteraction.user.id != interaction.member.user.id) return; 258 | if (!newInteraction.customId.startsWith('hentai')) return; 259 | switch (newInteraction.customId) { 260 | case "hentai1": { 261 | return newInteraction.update({ embeds: [helpEmbed1], components: [row] }); 262 | } 263 | case "hentai2": { 264 | return newInteraction.update({ embeds: [helpEmbed2], components: [row] }); 265 | } 266 | } 267 | }); 268 | 269 | await sleep(60000); 270 | row = new ActionRowBuilder() 271 | .addComponents( 272 | new ButtonBuilder() 273 | .setCustomId('hentai1') 274 | .setEmoji('1️⃣') 275 | .setStyle(ButtonStyle.Primary) 276 | .setDisabled(true), 277 | new ButtonBuilder() 278 | .setCustomId('hentai2') 279 | .setEmoji('2️⃣') 280 | .setStyle(ButtonStyle.Primary) 281 | .setDisabled(true), 282 | ); 283 | await interaction.editReply({ components: [row] }); 284 | 285 | return; 286 | } 287 | else { 288 | if (input == null) { 289 | notfound = false; 290 | subreddit = REDDIT_ENABLED_HENTAI_SUBREDDITS[Math.floor(Math.random() * REDDIT_ENABLED_HENTAI_SUBREDDITS.length)]; 291 | } 292 | else if (REDDIT_ENABLED_HENTAI_SUBREDDITS.map(list => list.toLowerCase()).includes(input.toLowerCase()) == false) { 293 | notfound = true; 294 | subreddit = REDDIT_ENABLED_HENTAI_SUBREDDITS[Math.floor(Math.random() * REDDIT_ENABLED_HENTAI_SUBREDDITS.length)]; 295 | } 296 | else if (REDDIT_ENABLED_HENTAI_SUBREDDITS.map(list => list.toLowerCase()).includes(input.toLowerCase()) == true) { 297 | notfound = false; 298 | subreddit = input; 299 | } 300 | else { 301 | await interaction.reply({ content: "I dont know what, but something bad happened here. Try again and if it's still not working create an issue on GitHub:\nhttps://eckigerluca.com/darling/github", ephemeral: true }); 302 | } 303 | } 304 | 305 | interaction.commandData = { 306 | name: interaction.commandName, 307 | options: [interaction.options], 308 | other: [{ 309 | subreddit: subreddit, 310 | }], 311 | }; 312 | 313 | async function getHentai() { 314 | const response = await fetch(`https://reddit.com/r/${subreddit}/random.json`); 315 | const data = await response.json(); 316 | 317 | let permalink; 318 | let subredditName; 319 | let hentaiUrl; 320 | let hentaiImg; 321 | let hentaiTitle; 322 | let hentaiUpvotes; 323 | let hentaiDownvotes; 324 | let hentaiNumComents; 325 | let hentaiSubredditUrl; 326 | let isVideo; 327 | 328 | if (data.kind == 'Listing') { 329 | const post = data.data.children[Math.floor(Math.random() * data.data.dist) - 1].data; 330 | logger.debug(post); 331 | permalink = post.permalink; 332 | subredditName = post.subreddit_name_prefixed; 333 | hentaiUrl = `https://reddit.com${permalink}`; 334 | hentaiImg = post.url; 335 | hentaiTitle = post.title; 336 | hentaiUpvotes = post.ups; 337 | hentaiDownvotes = post.downs; 338 | hentaiNumComents = post.num_comments; 339 | hentaiSubredditUrl = `https://reddit.com/r/${post.subreddit}`; 340 | isVideo = post.is_video; 341 | 342 | if (post.is_gallery == true) { 343 | const ImgCode = post.gallery_data.items[0].media_id; 344 | let ImgType; 345 | if (post.media_metadata[ImgCode].m == "image/jpg") { 346 | ImgType = "jpg"; 347 | } 348 | else if (post.media_metadata[ImgCode].m == "image/png") { 349 | ImgType = "png"; 350 | } 351 | hentaiImg = `https://i.redd.it/${ImgCode}.${ImgType}`; 352 | } 353 | } else { 354 | permalink = data[0].data.children[0].data.permalink; 355 | subredditName = data[0].data.children[0].data.subreddit_name_prefixed; 356 | hentaiUrl = `https://reddit.com${permalink}`; 357 | hentaiImg = data[0].data.children[0].data.url; 358 | hentaiTitle = data[0].data.children[0].data.title; 359 | hentaiUpvotes = data[0].data.children[0].data.ups; 360 | hentaiDownvotes = data[0].data.children[0].data.downs; 361 | hentaiNumComents = data[0].data.children[0].data.num_comments; 362 | hentaiSubredditUrl = `https://reddit.com/r/${data[0].data.children[0].data.subreddit}`; 363 | isVideo = data[0].data.children[0].data.is_video; 364 | 365 | if (data[0].data.children[0].data.is_gallery == true) { 366 | const ImgCode = data[0].data.children[0].data.gallery_data.items[0].media_id; 367 | let ImgType; 368 | if (data[0].data.children[0].data.media_metadata[ImgCode].m == "image/jpg") { 369 | ImgType = "jpg"; 370 | } 371 | else if (data[0].data.children[0].data.media_metadata[ImgCode].m == "image/png") { 372 | ImgType = "png"; 373 | } 374 | hentaiImg = `https://i.redd.it/${ImgCode}.${ImgType}`; 375 | } 376 | } 377 | 378 | const hentaiData = { 379 | 'permalink': permalink, 380 | 'postUrl': hentaiUrl, 381 | 'imgUrl': hentaiImg, 382 | 'title': hentaiTitle, 383 | 'upvotes': hentaiUpvotes, 384 | 'downvotes': hentaiDownvotes, 385 | 'comments': hentaiNumComents, 386 | 'subredditUrl': hentaiSubredditUrl, 387 | 'subredditName': subredditName, 388 | 'video': isVideo, 389 | }; 390 | return hentaiData; 391 | } 392 | let hentaiDataJson; 393 | do { 394 | hentaiDataJson = await getHentai(subreddit); 395 | } while (hentaiDataJson.video == true); 396 | 397 | if (hentaiDataJson.imgUrl.includes('redgif')) { 398 | await interaction.reply({ content: `This looks like a bit more!\n**From:** ${hentaiDataJson.subredditUrl}\n**Post:** ${hentaiDataJson.postUrl}\n**Submission:** ${hentaiDataJson.imgUrl}` }); 399 | } 400 | else { 401 | 402 | const embed = new EmbedBuilder() 403 | .setColor(color) 404 | .setTitle(hentaiDataJson.title) 405 | .setDescription(`From [${hentaiDataJson.subredditName}](${hentaiDataJson.subredditUrl})`) 406 | .setURL(hentaiDataJson.postUrl) 407 | .setImage(hentaiDataJson.imgUrl) 408 | .setFooter({ text: `👍 ${hentaiDataJson.upvotes} 👎 ${hentaiDataJson.downvotes} 💬 ${hentaiDataJson.comments}` }); 409 | 410 | await interaction.reply({ embeds: [embed] }); 411 | if (notfound == true) { 412 | const infoEmbed = new EmbedBuilder() 413 | .setTitle('404 Not Found') 414 | .setDescription("Seems like, that you've tried to get something from a subreddit that is not in the list!\nThat's why I decided to throw random shit..\nAnyway, you can see all supported subreddits with `/hentai help`") 415 | .setColor(color); 416 | await interaction.followUp({ embeds: [infoEmbed], ephemeral: true }); 417 | } 418 | } 419 | } 420 | else { await interaction.reply({ content: 'Please go to a channel that is marked as NSFW!', ephemeral: true }); return; } 421 | }, 422 | }; 423 | --------------------------------------------------------------------------------