Compare commits
No commits in common. "Slash-V14" and "akairo" have entirely different histories.
20
.env.example
|
@ -1,20 +0,0 @@
|
||||||
token=YourToken
|
|
||||||
clientId=BotClientId
|
|
||||||
guildId=DevGuildId
|
|
||||||
ownerId=OwnerUserId
|
|
||||||
statusChannel=CHannelIdForStatus
|
|
||||||
uptimeURL=UptimeKumaOrWhateverStatusThingYouUseOrJustLeaveEmpty
|
|
||||||
uptimeInterval=60
|
|
||||||
twiConsumer=TwitterConsumerToken
|
|
||||||
twiConsumerSecret=TwitterConsumerSecretToken
|
|
||||||
twiToken=TwitterToken
|
|
||||||
twiTokenSecret=TwitterSecretToken
|
|
||||||
twiChannel=ChannelWhereJustTheTwitterLinkAreSent
|
|
||||||
twiLogChannel=ChannelWhereTheDetailedInfoOfTheCommandIsSent
|
|
||||||
botsggToken=APITokenForBots.gg
|
|
||||||
botsggEndpoint=https://discord.bots.gg/api/v1
|
|
||||||
stableHordeApi=0000000000
|
|
||||||
stableHordeID=0000
|
|
||||||
NODE_ENV=development
|
|
||||||
ytdlpMaxResolution=720
|
|
||||||
proxy=socks5://localhost:3128
|
|
28
.eslintrc.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2018,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-console": [
|
||||||
|
"off"
|
||||||
|
],
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
"tab"
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"semi": [
|
||||||
|
"error",
|
||||||
|
"always"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
37
.github/ISSUE_TEMPLATE/bug.md
vendored
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
name: "Bug"
|
|
||||||
about: "Use this if you found a bug in the bot."
|
|
||||||
title: "[BUG] "
|
|
||||||
ref: "main"
|
|
||||||
labels:
|
|
||||||
|
|
||||||
- bug
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Please provide the commit of the bot at the time of the report. You can find it by doing /about or haha about. -->
|
|
||||||
**Commit number**
|
|
||||||
|
|
||||||
**Bot varient**
|
|
||||||
<!-- Put a x between the brackets to signify the version you used. -->
|
|
||||||
- [ ] Slash <!-- The current and latest version that use the slash commands. -->
|
|
||||||
- [ ] Legacy <!-- The old version of the bot with the "haha" prefix. -->
|
|
||||||
|
|
||||||
**Describe the issue**
|
|
||||||
|
|
||||||
**Intended result**
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
|
|
||||||
**Steps to reproduce the issue**
|
|
||||||
|
|
||||||
-
|
|
||||||
-
|
|
||||||
-
|
|
||||||
-
|
|
||||||
|
|
||||||
**Did someone already report that bug?**
|
|
||||||
|
|
||||||
- [ ] Yes <!-- If you have to put yes you don't need to submit that bug report. -->
|
|
||||||
- [ ] No
|
|
19
.github/ISSUE_TEMPLATE/feature.md
vendored
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
name: "Feature request"
|
|
||||||
about: "Use this if you want a new feature in the bot."
|
|
||||||
title: "[Feature request] "
|
|
||||||
ref: "main"
|
|
||||||
labels:
|
|
||||||
|
|
||||||
- Feature request
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the feature you want**
|
|
||||||
|
|
||||||
|
|
||||||
**Did someone already request that feature?**
|
|
||||||
|
|
||||||
- [ ] Yes <!-- If you have to put yes you don't need to submit that feature request. -->
|
|
||||||
- [ ] No
|
|
67
.gitignore
vendored
|
@ -1,16 +1,55 @@
|
||||||
.env
|
# root /
|
||||||
node_modules/
|
|
||||||
config/config.json
|
|
||||||
json/board/
|
|
||||||
unloaded/
|
|
||||||
database.sqlite3
|
|
||||||
tmp/*.js
|
|
||||||
|
|
||||||
bin/yt-dlp*
|
config.json
|
||||||
bin/HandBrakeCLI*
|
.DS_Store
|
||||||
bin/upload.sh
|
node_modules
|
||||||
bin/dectalk
|
.vscode
|
||||||
|
error/
|
||||||
|
|
||||||
asset/ytp/sources
|
# video
|
||||||
asset/ytp/music
|
|
||||||
asset/ytp/sounds
|
video.mp4
|
||||||
|
videoReady.mp4
|
||||||
|
SPOILER_video.mp4
|
||||||
|
SPOILER_videoReady.mp4
|
||||||
|
|
||||||
|
## images
|
||||||
|
|
||||||
|
img/frame001.png
|
||||||
|
img/spb.png
|
||||||
|
img/de.png
|
||||||
|
img/nolight.png
|
||||||
|
img/memeInput.gif
|
||||||
|
img/meme.gif
|
||||||
|
spb.png
|
||||||
|
|
||||||
|
### audio
|
||||||
|
|
||||||
|
tts.mp3
|
||||||
|
ttsvc.mp3
|
||||||
|
music.mp3
|
||||||
|
dectalk.wav
|
||||||
|
dectalkvc.wav
|
||||||
|
sam.wav
|
||||||
|
samvc.wav
|
||||||
|
|
||||||
|
# json
|
||||||
|
|
||||||
|
json/blacklist.json
|
||||||
|
json/customresponse.json
|
||||||
|
board/*.json
|
||||||
|
tag/*.json
|
||||||
|
welcome/*.json
|
||||||
|
bye/*.json
|
||||||
|
webhook/*.json
|
||||||
|
json/censor.json
|
||||||
|
json/uncensor.json
|
||||||
|
|
||||||
|
# other
|
||||||
|
dectalk/
|
||||||
|
*_unloaded.js
|
||||||
|
asset/ytp/userVid/*.mp4
|
||||||
|
asset/ytp/music/
|
||||||
|
asset/ytp/resources/
|
||||||
|
asset/ytp/sounds/
|
||||||
|
asset/ytp/sources/
|
17
.vscode/launch.json
vendored
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "pwa-node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Launch Program",
|
|
||||||
"skipFiles": [
|
|
||||||
"<node_internals>/**"
|
|
||||||
],
|
|
||||||
"program": "${workspaceFolder}/index.js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
83
README.md
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# Haha Yes
|
||||||
|
|
||||||
|
A multi function discord bot.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
These instructions will get you a copy of the project up and running on your local machine
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
You need to install the following
|
||||||
|
|
||||||
|
|
||||||
|
* https://github.com/Automattic/node-canvas
|
||||||
|
* sequelize-cli (``npm install -g sequelize-cli``)
|
||||||
|
* mysql
|
||||||
|
* ffmpeg (Optional but recommanded: for all command that require to interact with voice chat and [vid2gif.js](commands/utility/vid2gif.js), [vidshittyfier.js](commands/fun/vidshittyfier.js) and [ytp.js](commands/fun/ytp.js))
|
||||||
|
* handbrake-cli (Optional but recommanded: for [download.js](commands/utility/download.js))
|
||||||
|
* apngasm (Optional: for [nolight.js](commands/images/nolight))
|
||||||
|
* [Google credentials](https://cloud.google.com/docs/authentication/getting-started) (Optional: for [tts.js](commands/fun/tts/tts.js) and [ttsvc.js](commands/fun/tts/ttsvc.js), without that it will spam error on startup but not important)
|
||||||
|
* Wine (Optional: required for linux/mac for [dectalk.js](commands/fun/tts/dectalk.js) and [dectalkvc.js](commands/fun/tts/dectalkvc.js))
|
||||||
|
* xvfb (Optional: for wine if using headless server)
|
||||||
|
* waon (Optional: used to convert sound files to midi for [midify.js](commands/fun/midify.js))
|
||||||
|
* timidity (Optional: used to convert the midi files back to mp3 for [midify.js](commands/fun/midify.js))
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
```
|
||||||
|
git clone https://git.namejeff.xyz/Supositware/Haha-Yes
|
||||||
|
cd discordbot
|
||||||
|
npm install
|
||||||
|
|
||||||
|
sequelize db:migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
If the youtube-dl module didn't install youtube-dl by himself you can go in ``node_modules/youtube-dl/scripts`` and run ``node download.js``
|
||||||
|
Configure [config.json](config-exemple.jsonc) and [config/config.json](config/config-example.json )
|
||||||
|
|
||||||
|
To run the bot either use pm2
|
||||||
|
```
|
||||||
|
npm install -g pm2
|
||||||
|
pm2 start index.js --name(insert name)
|
||||||
|
```
|
||||||
|
or with node ``node index.js``
|
||||||
|
|
||||||
|
If on linux you can also do
|
||||||
|
|
||||||
|
``nohup node index.js &``
|
||||||
|
|
||||||
|
To use [ytp.js](commands/fun/ytp.js)
|
||||||
|
1. Download the folder 'sounds', 'music', 'resources', 'sources' from [YTPPlus](https://github.com/philosophofee/YTPPlus)
|
||||||
|
2. Put them in the [asset/ytp](asset/ytp) folder
|
||||||
|
|
||||||
|
To use dectalk on linux you will need
|
||||||
|
1. Get dectalk
|
||||||
|
2. install wine
|
||||||
|
3. install Xvfb & run `Xvfb :0 -screen 0 1024x768x16 &`
|
||||||
|
|
||||||
|
## Built With
|
||||||
|
|
||||||
|
* [Discord.JS](https://github.com/discordjs/discord.js) - The discord api used
|
||||||
|
* [Discord-Akairo](https://github.com/1Computer1/discord-akairo) - The framework used for Discord.JS
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
* **Loïc Bersier**
|
||||||
|
|
||||||
|
## Donation link
|
||||||
|
|
||||||
|
[![Paypal](https://www.paypalobjects.com/en_US/CH/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/paypalme2/supositware/)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the **GNU Affero General Public License v3.0** License - see the [LICENSE](LICENSE) file for details
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
* [discord.JS team](https://github.com/discordjs/discord.js)
|
||||||
|
* [1computer1](https://github.com/1Computer1/) for discord-akairo & the help command from [hoshi](https://github.com/1Computer1/hoshi)
|
||||||
|
* [Rantionary](https://github.com/RantLang/Rantionary) for there dictionnary.
|
||||||
|
* Tina the Cyclops girl#0064 for inspiring me for making this bot
|
||||||
|
* [Jetbrains](https://www.jetbrains.com/?from=Hahayesdiscordbot) for providing their IDE free of charges!
|
||||||
|
|
||||||
|
<img src="https://its.gamingti.me/XT8F.svg" width=20%></img>
|
BIN
asset/img/command/admin/commandblock.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
asset/img/command/admin/shameboard.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
asset/img/command/admin/starboard.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
asset/img/command/admin/tag.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
asset/img/command/fun/4chan.png
Normal file
After Width: | Height: | Size: 258 KiB |
BIN
asset/img/command/fun/audio2image.png
Normal file
After Width: | Height: | Size: 283 KiB |
BIN
asset/img/command/fun/fakebot.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
asset/img/command/fun/image2audio.png
Normal file
After Width: | Height: | Size: 147 KiB |
BIN
asset/img/command/fun/midify.png
Normal file
After Width: | Height: | Size: 172 KiB |
BIN
asset/img/command/fun/reddit.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
asset/img/command/fun/vidshittifier.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
asset/img/command/general/randomizer.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
asset/img/command/general/say.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
asset/img/command/utility/color.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
asset/img/command/utility/download.png
Normal file
After Width: | Height: | Size: 401 KiB |
BIN
asset/img/command/utility/feedback.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
asset/img/command/utility/gif2vid.png
Normal file
After Width: | Height: | Size: 164 KiB |
BIN
asset/img/command/utility/screenshot.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
asset/img/command/utility/seetag.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
asset/img/command/utility/strawpoll.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
asset/img/command/utility/translate.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
asset/img/command/utility/userInfo.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
asset/img/command/utility/vid2gif.png
Normal file
After Width: | Height: | Size: 197 KiB |
BIN
asset/img/command/utility/wallpaper.png
Normal file
After Width: | Height: | Size: 259 KiB |
BIN
asset/img/frame002.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
asset/img/gold.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
asset/impact.ttf
Normal file
BIN
asset/times.ttf
Normal file
1
asset/timidity/config/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# You Will need to edit the config files to includes absolute path
|
1
asset/timidity/config/noteblock.cfg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
soundfont /restricted/hahayes/hahaTest/asset/timidity/sf/MCNBS_3_3_4.sf2
|
1
asset/timidity/config/voice.cfg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
soundfont /restricted/hahayes/hahaTest/asset/timidity/sf/E3Kay_s_Epic_Soundfont.sf2
|
BIN
asset/timidity/sf/E3Kay_s_Epic_Soundfont.sf2
Normal file
BIN
asset/timidity/sf/MCNBS_3_3_4.sf2
Normal file
6
asset/timidity/sf/README.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
MCNBS_3_3_4.sf2 - [Creative Commons Attribution 4.0 International](https://creativecommons.org/licenses/by/4.0/deed.en) Author: Stuff by David
|
||||||
|
|
||||||
|
|
||||||
|
E3Kay's Epic Soundfont - [Creative Commons Attribution 3.0 Unported](http://creativecommons.org/licenses/by-3/4.0/deed.en) Author: E3Kay
|
BIN
asset/vid/You_Have_Been_Banned_From_Mickey_Mouse_Club.mp4
Normal file
|
@ -1,171 +0,0 @@
|
||||||
/* TODO
|
|
||||||
*
|
|
||||||
* To be merged with commands/AI/txt2img.js
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
import { SlashCommandBuilder, EmbedBuilder, AttachmentBuilder, ButtonBuilder, ActionRowBuilder, ButtonStyle } from 'discord.js';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
import os from 'node:os';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import stream from 'node:stream';
|
|
||||||
import util from 'node:util';
|
|
||||||
|
|
||||||
import db from '../../models/index.js';
|
|
||||||
|
|
||||||
const { stableHordeApi, stableHordeID } = process.env;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('img2img')
|
|
||||||
.setDescription('AI generated image with stable diffusion (If credit are low it may be slow)')
|
|
||||||
.addAttachmentOption(option =>
|
|
||||||
option.setName('image')
|
|
||||||
.setDescription('Image you want to modify')
|
|
||||||
.setRequired(true))
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('prompt')
|
|
||||||
.setDescription('What do you want the AI to generate?')
|
|
||||||
.setRequired(true)),
|
|
||||||
category: 'AI',
|
|
||||||
alias: ['i2i'],
|
|
||||||
async execute(interaction, args, client) {
|
|
||||||
await interaction.deferReply();
|
|
||||||
|
|
||||||
const streamPipeline = util.promisify(stream.pipeline);
|
|
||||||
const res = await fetch(args.image.url);
|
|
||||||
if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.');
|
|
||||||
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${args.image.name}.webp`));
|
|
||||||
|
|
||||||
const b64Image = fs.readFileSync(`${os.tmpdir()}/${args.image.name}.webp`, { encoding: 'base64' });
|
|
||||||
generate(interaction, args.prompt, client, b64Image);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async function generate(i, prompt, client, b64Img) {
|
|
||||||
console.log('Generating image');
|
|
||||||
const body = {
|
|
||||||
prompt: prompt,
|
|
||||||
params: {
|
|
||||||
n: 1,
|
|
||||||
width: 512,
|
|
||||||
height: 512,
|
|
||||||
},
|
|
||||||
cfg_scale: 9,
|
|
||||||
use_gfpgan: true,
|
|
||||||
use_real_esrgan: true,
|
|
||||||
use_ldsr: true,
|
|
||||||
use_upscaling: true,
|
|
||||||
steps: 50,
|
|
||||||
nsfw: i.channel.nsfw ? true : false,
|
|
||||||
censor_nsfw: i.channel.nsfw ? true : false,
|
|
||||||
source_image: b64Img,
|
|
||||||
source_processing: 'img2img',
|
|
||||||
shared: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const isOptOut = await db.optout.findOne({ where: { userID: i.user.id } });
|
|
||||||
|
|
||||||
if (isOptOut) {
|
|
||||||
body.shared = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchParameters = {
|
|
||||||
method: 'post',
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
headers: { 'Content-Type': 'application/json', 'apikey': stableHordeApi },
|
|
||||||
};
|
|
||||||
|
|
||||||
let response = await fetch('https://stablehorde.net/api/v2/generate/async', fetchParameters);
|
|
||||||
|
|
||||||
response = await response.json();
|
|
||||||
|
|
||||||
if (!response.id) {
|
|
||||||
console.log(response);
|
|
||||||
return i.editReply({ content: `An error has occured, please try again later. \`${response.message}\`` });
|
|
||||||
}
|
|
||||||
|
|
||||||
let wait_time = 5000;
|
|
||||||
let checkURL = `https://stablehorde.net/api/v2/generate/check/${response.id}`;
|
|
||||||
const checking = setInterval(async () => {
|
|
||||||
const checkResult = await checkGeneration(checkURL);
|
|
||||||
|
|
||||||
if (checkResult === undefined) return;
|
|
||||||
if (!checkResult.done) {
|
|
||||||
if (checkResult.wait_time === -1) {
|
|
||||||
console.log(checkResult.raw);
|
|
||||||
return i.editReply({ content: `An error has occured, please try again later. \`${checkResult.raw.message}\`` });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkResult.wait_time < 0) {
|
|
||||||
console.log(checkResult.raw);
|
|
||||||
clearInterval(checking);
|
|
||||||
return i.editReply({ content: 'No servers are currently available to fulfill your request, please try again later.' });
|
|
||||||
}
|
|
||||||
if (checkResult.wait_time === 0) {
|
|
||||||
checkURL = `https://stablehorde.net/api/v2/generate/status/${response.id}`;
|
|
||||||
}
|
|
||||||
wait_time = checkResult.wait_time;
|
|
||||||
}
|
|
||||||
else if (checkResult.done && checkResult.image) {
|
|
||||||
clearInterval(checking);
|
|
||||||
let creditResponse = await fetch(`https://stablehorde.net/api/v2/users/${stableHordeID}`);
|
|
||||||
creditResponse = await creditResponse.json();
|
|
||||||
|
|
||||||
const streamPipeline = util.promisify(stream.pipeline);
|
|
||||||
const res = await fetch(checkResult.image);
|
|
||||||
if (!res.ok) return i.editReply('An error has occured while trying to download your image.');
|
|
||||||
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${i.id}.webp`));
|
|
||||||
|
|
||||||
const generatedImg = new AttachmentBuilder(`${os.tmpdir()}/${i.id}.webp`);
|
|
||||||
|
|
||||||
const stableEmbed = new EmbedBuilder()
|
|
||||||
.setColor(i.member ? i.member.displayHexColor : 'Navy')
|
|
||||||
.setTitle(prompt)
|
|
||||||
.setURL('https://aqualxx.github.io/stable-ui/')
|
|
||||||
.setImage(`attachment://${i.id}.webp`)
|
|
||||||
.setFooter({ text: `**Credit left: ${creditResponse.kudos}** Seed: ${checkResult.seed} worker ID: ${checkResult.worker_id} worker name: ${checkResult.worker_name}` });
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`regenerate${i.user.id}${i.id}`)
|
|
||||||
.setLabel('🔄 Regenerate')
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
);
|
|
||||||
|
|
||||||
await i.editReply({ embeds: [stableEmbed], components: [row], files: [generatedImg] });
|
|
||||||
|
|
||||||
listenButton(client, i, prompt);
|
|
||||||
}
|
|
||||||
}, wait_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkGeneration(url) {
|
|
||||||
let check = await fetch(url);
|
|
||||||
check = await check.json();
|
|
||||||
|
|
||||||
if (!check.is_possible) {
|
|
||||||
return { done: false, wait_time: -1, raw: check };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check.done) {
|
|
||||||
if (!check.generations) {
|
|
||||||
return { done: false, wait_time: check.wait_time * 1000, raw: check };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { done: true, image: check.generations[0].img, seed: check.generations[0].seed, worker_id: check.generations[0].worker_id, worker_name: check.generations[0].worker_name, raw: check };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function listenButton(client, interaction, prompt) {
|
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
await interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `regenerate${interactionMenu.user.id}${interaction.id}`) {
|
|
||||||
await interactionMenu.deferReply();
|
|
||||||
await generate(interactionMenu, prompt, client);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
/* TODO
|
|
||||||
*
|
|
||||||
* To be merged with commands/AI/img2img.js
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
import { SlashCommandBuilder, EmbedBuilder, AttachmentBuilder, ButtonBuilder, ActionRowBuilder, ButtonStyle } from 'discord.js';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
import os from 'node:os';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import stream from 'node:stream';
|
|
||||||
import util from 'node:util';
|
|
||||||
|
|
||||||
import db from '../../models/index.js';
|
|
||||||
|
|
||||||
const { stableHordeApi, stableHordeID } = process.env;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('txt2img')
|
|
||||||
.setDescription('AI generated image with stable diffusion (If credit are low it may be slow)')
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('prompt')
|
|
||||||
.setDescription('What do you want the AI to generate?')
|
|
||||||
.setRequired(true)),
|
|
||||||
category: 'AI',
|
|
||||||
alias: ['t2i'],
|
|
||||||
async execute(interaction, args, client) {
|
|
||||||
await interaction.deferReply();
|
|
||||||
generate(interaction, args.prompt, client);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async function generate(i, prompt, client) {
|
|
||||||
const body = {
|
|
||||||
prompt: prompt,
|
|
||||||
params: {
|
|
||||||
n: 1,
|
|
||||||
width: 512,
|
|
||||||
height: 512,
|
|
||||||
},
|
|
||||||
cfg_scale: 9,
|
|
||||||
use_gfpgan: true,
|
|
||||||
use_real_esrgan: true,
|
|
||||||
use_ldsr: true,
|
|
||||||
use_upscaling: true,
|
|
||||||
steps: 50,
|
|
||||||
nsfw: i.channel.nsfw ? true : false,
|
|
||||||
censor_nsfw: i.channel.nsfw ? true : false,
|
|
||||||
shared: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const isOptOut = await db.optout.findOne({ where: { userID: i.user.id } });
|
|
||||||
|
|
||||||
if (isOptOut) {
|
|
||||||
body.shared = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchParameters = {
|
|
||||||
method: 'post',
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
headers: { 'Content-Type': 'application/json', 'apikey': stableHordeApi },
|
|
||||||
};
|
|
||||||
|
|
||||||
let response = await fetch('https://stablehorde.net/api/v2/generate/async', fetchParameters);
|
|
||||||
|
|
||||||
response = await response.json();
|
|
||||||
let wait_time = 5000;
|
|
||||||
let checkURL = `https://stablehorde.net/api/v2/generate/check/${response.id}`;
|
|
||||||
const checking = setInterval(async () => {
|
|
||||||
const checkResult = await checkGeneration(checkURL);
|
|
||||||
|
|
||||||
if (checkResult === undefined) return;
|
|
||||||
if (!checkResult.done) {
|
|
||||||
if (checkResult.wait_time < 0) {
|
|
||||||
clearInterval(checking);
|
|
||||||
return i.editReply({ content: 'No servers are currently available to fulfill your request, please try again later.' });
|
|
||||||
}
|
|
||||||
if (checkResult.wait_time === 0) {
|
|
||||||
checkURL = `https://stablehorde.net/api/v2/generate/status/${response.id}`;
|
|
||||||
}
|
|
||||||
wait_time = checkResult.wait_time;
|
|
||||||
}
|
|
||||||
else if (checkResult.done && checkResult.image) {
|
|
||||||
clearInterval(checking);
|
|
||||||
let creditResponse = await fetch(`https://stablehorde.net/api/v2/users/${stableHordeID}`);
|
|
||||||
creditResponse = await creditResponse.json();
|
|
||||||
|
|
||||||
const streamPipeline = util.promisify(stream.pipeline);
|
|
||||||
const res = await fetch(checkResult.image);
|
|
||||||
if (!res.ok) return i.editReply('An error has occured while trying to download your image.');
|
|
||||||
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${i.id}.webp`));
|
|
||||||
|
|
||||||
const generatedImg = new AttachmentBuilder(`${os.tmpdir()}/${i.id}.webp`);
|
|
||||||
|
|
||||||
const stableEmbed = new EmbedBuilder()
|
|
||||||
.setColor(i.member ? i.member.displayHexColor : 'Navy')
|
|
||||||
.setTitle(prompt)
|
|
||||||
.setURL('https://aqualxx.github.io/stable-ui/')
|
|
||||||
.setImage(`attachment://${i.id}.webp`)
|
|
||||||
.setFooter({ text: `**Credit left: ${creditResponse.kudos}** Seed: ${checkResult.seed} worker ID: ${checkResult.worker_id} worker name: ${checkResult.worker_name}` });
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`regenerate${i.user.id}${i.id}`)
|
|
||||||
.setLabel('🔄 Regenerate')
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
);
|
|
||||||
|
|
||||||
await i.editReply({ embeds: [stableEmbed], components: [row], files: [generatedImg] });
|
|
||||||
|
|
||||||
listenButton(client, i, prompt);
|
|
||||||
}
|
|
||||||
}, wait_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkGeneration(url) {
|
|
||||||
let check = await fetch(url);
|
|
||||||
check = await check.json();
|
|
||||||
|
|
||||||
if (!check.is_possible) {
|
|
||||||
return { done: false, wait_time: -1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check.done) {
|
|
||||||
if (!check.generations) {
|
|
||||||
return { done: false, wait_time: check.wait_time * 1000 };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { done: true, image: check.generations[0].img, seed: check.generations[0].seed, worker_id: check.generations[0].worker_id, worker_name: check.generations[0].worker_name };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function listenButton(client, interaction, prompt) {
|
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
await interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `regenerate${interactionMenu.user.id}${interaction.id}`) {
|
|
||||||
await interactionMenu.deferReply();
|
|
||||||
await generate(interactionMenu, prompt, client);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,62 +1,45 @@
|
||||||
import { SlashCommandBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, PermissionFlagsBits } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import db from '../../models/index.js';
|
const autoResponseStat = require('../../models').autoresponseStat;
|
||||||
|
|
||||||
export default {
|
class autoresponseCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('autoresponse')
|
super('autoresponse', {
|
||||||
.setDescription('Enable or disable autoresponse')
|
aliases: ['autoresponse'],
|
||||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
async execute(interaction, args, client) {
|
args: [
|
||||||
const autoresponseStat = await db.autoresponseStat.findOne({ where: { serverID: interaction.guild.id } });
|
{
|
||||||
if (!autoresponseStat) {
|
id: 'stat',
|
||||||
const body = { serverID: interaction.guild.id, stat: 'enable' };
|
type: 'string',
|
||||||
await db.autoresponseStat.create(body);
|
prompt: {
|
||||||
return await interaction.reply({ content: 'Autoresponse has been enabled.', ephemeral: true });
|
start: 'Do you want to **enable** or **disable** auto response?',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`yes${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Yes')
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`no${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('No')
|
|
||||||
.setStyle(ButtonStyle.Danger),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (autoresponseStat.stat === 'enable') {
|
|
||||||
await interaction.reply({ content: 'Autoresponse is already enabled, do you wish to disable it?', components: [row], ephemeral: true });
|
|
||||||
}
|
}
|
||||||
else {
|
],
|
||||||
const body = { serverID: interaction.guild.id, stat: 'enable' };
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
await db.autoresponseStat.update(body, { where: { serverID: interaction.guild.id } });
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
return interaction.editReply({ content: 'Auto response has been enabled.', ephemeral: true });
|
channel: 'guild',
|
||||||
}
|
description: {
|
||||||
|
content: 'enable/disable autoresponse',
|
||||||
return listenButton(client, interaction, interaction.user);
|
usage: '[enable/disable]',
|
||||||
},
|
examples: ['enable']
|
||||||
};
|
|
||||||
|
|
||||||
async function listenButton(client, interaction, user = interaction.user, originalId = interaction.id) {
|
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
|
||||||
if (user !== interactionMenu.user) return listenButton(client, interaction, user, originalId);
|
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
await interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `yes${interaction.user.id}${originalId}`) {
|
|
||||||
const body = { serverID: interaction.guild.id, stat: 'disable' };
|
|
||||||
await db.autoresponseStat.update(body, { where: { serverID: interaction.guild.id } });
|
|
||||||
return interaction.editReply({ content: 'Auto response has been disabled.', ephemeral: true });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply({ content: 'Nothing has been changed.', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (args.stat.toLowerCase() == 'enable' || args.stat.toLowerCase() == 'disable') {
|
||||||
|
const autoresponseStat = await autoResponseStat.findOne({where: {serverID: message.guild.id}});
|
||||||
|
|
||||||
|
if (!autoresponseStat) {
|
||||||
|
const body = {serverID: message.guild.id, stat: args.stat};
|
||||||
|
autoResponseStat.create(body);
|
||||||
|
return message.channel.send(`Autoresponse have been ${args.stat}d`);
|
||||||
|
} else {
|
||||||
|
const body = {serverID: message.guild.id, stat: args.stat};
|
||||||
|
autoResponseStat.update(body, {where: {serverID: message.guild.id}});
|
||||||
|
return message.channel.send(`Autoresponse have been ${args.stat}d`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = autoresponseCommand;
|
70
commands/admin/ban.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class BanCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('ban', {
|
||||||
|
aliases: ['ban'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'user',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'which user do you want to ban?',
|
||||||
|
retry: 'This doesn\'t look like a user, please try again!'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reasons',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'For what reasons?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['BAN_MEMBERS', 'SEND_MESSAGES'],
|
||||||
|
userPermissions: ['BAN_MEMBERS'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Ban user | For hackban precise the userid',
|
||||||
|
usage: '[@user] [reason] OR [userID] [reason]',
|
||||||
|
examples: ['@user big dumb dumb', 'userID hackban']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let reasons = args.reasons;
|
||||||
|
let user = args.user;
|
||||||
|
if (message.mentions.members.first())
|
||||||
|
user = message.mentions.members.first().id;
|
||||||
|
|
||||||
|
if(user === this.client.user.id)
|
||||||
|
return message.channel.send('Can\'t ban me fool!');
|
||||||
|
if(!reasons)
|
||||||
|
reasons = 'Nothing have been specified';
|
||||||
|
if(user === message.author.id)
|
||||||
|
return message.channel.send('Why would you ban yourself ?');
|
||||||
|
|
||||||
|
if (message.mentions.members.first()) {
|
||||||
|
user = message.mentions.members.first();
|
||||||
|
await user.send(`You have been banned from **${message.guild.name}** for the following reasons: "**${reasons}**"`, {files: ['./asset/vid/You_Have_Been_Banned_From_Mickey_Mouse_Club.mp4']})
|
||||||
|
.catch(() => console.log('could not send message to the concerned user'));
|
||||||
|
|
||||||
|
return user.ban({reason: `Banned by : ${message.author.username} for the following reasons : ${reasons}`})
|
||||||
|
.then(() => message.reply(`${user.user.username} was succesfully banned with the following reasons "${reasons}".`))
|
||||||
|
//.catch(() => message.reply('Uh oh, an error has occurred! can the bot ban this user?'));
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
message.guild.members.ban(user, {reason: `Banned by : ${message.author.username} for the following reasons : ${reasons}`})
|
||||||
|
.then(() => message.reply(`user ID ${args.user} was succesfully hackbanned with the following reasons "${reasons}".`))
|
||||||
|
//.catch(() => message.reply('Uh oh, an error has occurred! can the bot ban this user?'));
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BanCommand;
|
71
commands/admin/banword.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const safe = require('safe-regex');
|
||||||
|
const BannedWords = require('../../models').bannedWords;
|
||||||
|
|
||||||
|
class BannedWordsCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('BannedWords', {
|
||||||
|
aliases: ['bannedword', 'banword', 'unbanword', 'censor', 'uncensor', 'blacklistword', 'blacklist', 'unblacklist'],
|
||||||
|
category: 'admin',
|
||||||
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
|
clientPermissions: ['MANAGE_MESSAGES', 'SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'word',
|
||||||
|
type: 'string',
|
||||||
|
match: 'rest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'remove',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--remove'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'removeall',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--removeall'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Ban word on the server. use the unbanword alias to delete a banned word, unbanword alias and --removeaall to remove every banned word',
|
||||||
|
usage: '[word to ban]',
|
||||||
|
examples: ['owo']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (!safe(message.content)) return;
|
||||||
|
|
||||||
|
if (!args.word) args.word = '';
|
||||||
|
args.word = args.word.replace(/[\u0250-\ue007]/g, '');
|
||||||
|
const bannedWords = await BannedWords.findOne({where: {word: args.word.toLowerCase(), serverID: message.guild.id}});
|
||||||
|
|
||||||
|
if (message.util.parsed.alias == 'unbanword' || message.util.parsed.alias == 'uncensor' || message.util.parsed.alias == 'unblacklist' || args.remove || args.removeall) {
|
||||||
|
if (args.removeall) {
|
||||||
|
BannedWords.destroy({where: {serverID: message.guild.id}});
|
||||||
|
return message.channel.send('The banned words have been reset.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bannedWords) {
|
||||||
|
BannedWords.destroy({where: {word: args.word.toLowerCase(), serverID: message.guild.id}});
|
||||||
|
return message.channel.send(`The word ${args.word.toLowerCase()} is no longer banned`);
|
||||||
|
} else {
|
||||||
|
return message.channel.send('There was no word to unban');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.word) return message.channel.send('Please specify a word to ban!');
|
||||||
|
|
||||||
|
if (!bannedWords) {
|
||||||
|
const body = {word: args.word.toLowerCase(), serverID: message.guild.id};
|
||||||
|
await BannedWords.create(body);
|
||||||
|
return message.channel.send(`The word ${args.word.toLowerCase()} has been banned`);
|
||||||
|
} else {
|
||||||
|
message.channel.send('This word is already banned');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BannedWordsCommand;
|
|
@ -1,74 +1,75 @@
|
||||||
import { SlashCommandBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, PermissionFlagsBits } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import db from '../../models/index.js';
|
const leaveChannel = require('../../models').leaveChannel;
|
||||||
|
|
||||||
export default {
|
class byeCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('bye')
|
super('bye', {
|
||||||
.setDescription('Set a leave message')
|
aliases: ['bye', 'leave'],
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('message')
|
|
||||||
.setDescription('The message you want the bot to say when someone leave in the current channel.')),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
userPermissions: [PermissionFlagsBits.ManageChannels],
|
channel: 'guild',
|
||||||
async execute(interaction, args, client) {
|
userPermissions: ['MANAGE_CHANNELS'],
|
||||||
const leave = await db.leaveChannel.findOne({ where: { guildID: interaction.guild.id } });
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
if (!leave && !args.message) {
|
{
|
||||||
return interaction.reply({ content: 'You need a message for me to say anything!', ephemeral: true });
|
id: 'remove',
|
||||||
}
|
match: 'flag',
|
||||||
else if (!leave) {
|
flag: '--remove'
|
||||||
const body = { guildID: interaction.guild.id, channelID: interaction.channel.id, message: args.message };
|
|
||||||
await db.leaveChannel.create(body);
|
|
||||||
return interaction.reply({ content: `The leave message have been set with ${args.message}`, ephemeral: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`edit${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Edit')
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`remove${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Remove')
|
|
||||||
.setStyle(ButtonStyle.Danger),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`nothing${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Do nothing')
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
);
|
|
||||||
|
|
||||||
await interaction.reply({ content: 'The server already has a message set, do you want to edit it or remove it?', components: [row], ephemeral: true });
|
|
||||||
|
|
||||||
return listenButton(client, interaction, args, interaction.user);
|
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
id: 'message',
|
||||||
async function listenButton(client, interaction, args, user = interaction.user, originalId = interaction.id) {
|
type: 'string',
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
match: 'rest',
|
||||||
if (user !== interactionMenu.user) return listenButton(client, interaction, args, user, originalId);
|
default: '[member] just left the server :('
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
await interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `edit${interaction.user.id}${originalId}`) {
|
|
||||||
if (!args.message) {
|
|
||||||
return interaction.reply({ content: 'You need to input a message for me to edit!', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
const body = { guildID: interaction.guild.id, channelID: interaction.channel.id, message: args.message };
|
],
|
||||||
await db.leaveChannel.update(body, { where: { guildID: interaction.guild.id } });
|
description: {
|
||||||
return interaction.editReply({ content: `The leave message has been set to ${args.message}`, ephemeral: true });
|
content: 'Send a message to the current channel when a person leave, you can use [member] to show the member username and [server] to show the name of the server',
|
||||||
}
|
usage: '[bye message]',
|
||||||
else if (interactionMenu.customId === `remove${interaction.user.id}${originalId}`) {
|
examples: ['[member] left the server, he deserve a ban']
|
||||||
db.leaveChannel.destroy({ where: { guildID: interaction.guild.id, channelID: interaction.channel.id } });
|
|
||||||
return interaction.editReply({ content: 'The leave message has been deleted.', ephemeral: true });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply({ content: 'Nothing has been changed.', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
const leave = await leaveChannel.findOne({where: {guildID: message.guild.id}});
|
||||||
|
|
||||||
|
if (args.remove) {
|
||||||
|
if (leave) {
|
||||||
|
leave.destroy({where: {guildID: message.guild.id, channelID: message.channel.id}});
|
||||||
|
return message.channel.send('successfully deleted the leave message');
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Did not find the a leave message, are you sure you have one setup?');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.message) {
|
||||||
|
return message.channel.send('Please provide a message');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!leave) {
|
||||||
|
const body = {guildID: message.guild.id, channelID: message.channel.id, message: args.message};
|
||||||
|
await leaveChannel.create(body);
|
||||||
|
return message.channel.send(`The leave message have been set with ${args.message}`);
|
||||||
|
} else {
|
||||||
|
message.channel.send('The server already have a leave message, do you want to replace it? y/n');
|
||||||
|
const filter = m => m.content && m.author.id == message.author.id;
|
||||||
|
message.channel.awaitMessages(filter, {time: 5000, max: 1, errors: ['time'] })
|
||||||
|
.then(async messages => {
|
||||||
|
let messageContent = messages.map(messages => messages.content);
|
||||||
|
if (messageContent[0] === 'y' || messageContent[0] === 'yes') {
|
||||||
|
const body = {guildID: message.guild.id, channelID: message.channel.id, message: args.message};
|
||||||
|
await leaveChannel.update(body, {where: {guildID: message.guild.id}});
|
||||||
|
return message.channel.send(`The leave message have been set with ${args.message}`);
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Not updating.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Took too long to answer. didin\'t update anything.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = byeCommand;
|
45
commands/admin/commandblock.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const commandblock = require('../../models').commandBlock;
|
||||||
|
|
||||||
|
class commandblockCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('commandblock', {
|
||||||
|
aliases: ['commandblock', 'blockcommand'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'command',
|
||||||
|
type: 'command',
|
||||||
|
prompt: {
|
||||||
|
start: 'What command do you want to block?',
|
||||||
|
retry: 'Not a valid command, please try again'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
userPermissions: ['ADMINISTRATOR'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Block a command. Execute that command again to unblock a command',
|
||||||
|
usage: '[command name]',
|
||||||
|
examples: ['owned']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (args.command.id == 'commandblock') return message.channel.send('Whoa there, i can\'t let you block this command or else how would you unblock it?');
|
||||||
|
|
||||||
|
const blocked = await commandblock.findOne({where: {serverID: message.guild.id, command: args.command.id}});
|
||||||
|
|
||||||
|
if (!blocked) {
|
||||||
|
const body = {serverID: message.guild.id, command: args.command.id};
|
||||||
|
commandblock.create(body);
|
||||||
|
return message.channel.send(`Blocked command ${args.command.id}`);
|
||||||
|
} else {
|
||||||
|
commandblock.destroy({where: {serverID: message.guild.id, command: args.command.id}});
|
||||||
|
return message.channel.send(`The command ${args.command.id} has been unblocked`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = commandblockCommand;
|
52
commands/admin/commandblockuser.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const commandblockuser = require('../../models').commandblockuser;
|
||||||
|
|
||||||
|
class commandblockuserCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('commandblockuser', {
|
||||||
|
aliases: ['commandblockuser', 'userblockcommand'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'command',
|
||||||
|
type: 'command',
|
||||||
|
prompt: {
|
||||||
|
start: 'What command do you want to block?',
|
||||||
|
retry: 'Not a valid command, please try again'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user',
|
||||||
|
type: 'user',
|
||||||
|
prompt: {
|
||||||
|
start: 'Which user you want to block?'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
userPermissions: ['ADMINISTRATOR'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Block a command from a user. Execute that command again to unblock a command',
|
||||||
|
usage: '[command name] [@user]',
|
||||||
|
examples: ['owned @supositware']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (args.command.id == 'commandblockuser') return message.channel.send('Whoa there, i can\'t let you block this command or else how would you unblock it?');
|
||||||
|
|
||||||
|
const blocked = await commandblockuser.findOne({where: {serverID: message.guild.id, userID: args.user.id, command: args.command.id}});
|
||||||
|
|
||||||
|
if (!blocked) {
|
||||||
|
const body = {serverID: message.guild.id, userID: args.user.id, command: args.command.id};
|
||||||
|
commandblockuser.create(body);
|
||||||
|
return message.channel.send(`Blocked command ${args.command.id}`);
|
||||||
|
} else {
|
||||||
|
commandblockuser.destroy({where: {serverID: message.guild.id, userID: args.user.id, command: args.command.id}});
|
||||||
|
return message.channel.send(`The command ${args.command.id} has been unblocked`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = commandblockuserCommand;
|
43
commands/admin/fakejoin.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const joinChannel = require('../../models').joinChannel;
|
||||||
|
|
||||||
|
class fakejoinCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('fakejoin', {
|
||||||
|
aliases: ['fakejoin'],
|
||||||
|
category: 'admin',
|
||||||
|
channel: 'guild',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'user',
|
||||||
|
type: 'user',
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Fake join message',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['Supositware']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let member;
|
||||||
|
const join = await joinChannel.findOne({where: {guildID: message.guild.id}});
|
||||||
|
|
||||||
|
if (join) {
|
||||||
|
if (args.user)
|
||||||
|
member = message.guild.members.resolve(args.user.id);
|
||||||
|
else
|
||||||
|
member = message.guild.members.resolve(message.author.id);
|
||||||
|
} else {
|
||||||
|
return message.reply('There is no join channel setup');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.emit('guildMemberAdd', member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = fakejoinCommand;
|
43
commands/admin/fakeleave.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const leaveChannel = require('../../models').leaveChannel;
|
||||||
|
|
||||||
|
class fakeleaveCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('fakeleave', {
|
||||||
|
aliases: ['fakeleave'],
|
||||||
|
category: 'admin',
|
||||||
|
channel: 'guild',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'user',
|
||||||
|
type: 'user',
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Fake leave message',
|
||||||
|
usage: '[user]',
|
||||||
|
examples: ['Supositware']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let member;
|
||||||
|
const leave = await leaveChannel.findOne({where: {guildID: message.guild.id}});
|
||||||
|
|
||||||
|
if (leave) {
|
||||||
|
if (args.user)
|
||||||
|
member = message.guild.members.resolve(args.user.id);
|
||||||
|
else
|
||||||
|
member = message.guild.members.resolve(message.author.id);
|
||||||
|
} else {
|
||||||
|
return message.reply('There is no leave channel setup');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.emit('guildMemberRemove', member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = fakeleaveCommand;
|
57
commands/admin/kick.js
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class KickCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('kick', {
|
||||||
|
aliases: ['kick'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'member',
|
||||||
|
type: 'member',
|
||||||
|
prompt: {
|
||||||
|
start: 'which member do you want to ban?',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reasons',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'For what reasons?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['KICK_MEMBERS', 'SEND_MESSAGES'],
|
||||||
|
userPermissions: ['KICK_MEMBERS'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Kick user',
|
||||||
|
usage: '[@user] [reason]',
|
||||||
|
examples: ['@user big dumb dumb']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let member = args.member;
|
||||||
|
let reasons = args.reasons;
|
||||||
|
|
||||||
|
if(member === this.client.user)
|
||||||
|
return message.channel.send('Cant kick me fool');
|
||||||
|
if(member.id === message.author.id)
|
||||||
|
return message.channel.send('Why would you kick yourself ?');
|
||||||
|
if(!reasons)
|
||||||
|
reasons = 'Nothing have been specified.';
|
||||||
|
|
||||||
|
await member.send(`You have been kicked from **${message.guild.name}** for the following reasons: "**${reasons}**"`)
|
||||||
|
.catch(() => console.log('could not send message to the concerned user'));
|
||||||
|
|
||||||
|
return member.kick({reason: `Kicked by : ${message.author.username} for the following reasons: ${reasons}`})
|
||||||
|
.then(() => message.reply(`${member.user.username} was succesfully kicked with the following reasons "${reasons}".`))
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = KickCommand;
|
51
commands/admin/log.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const LogStats = require('../../models').LogStats;
|
||||||
|
|
||||||
|
class logCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('log', {
|
||||||
|
aliases: ['log', 'logging'],
|
||||||
|
category: 'admin',
|
||||||
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
|
clientPermissions: ['MANAGE_GUILD'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Setup logging in current channel (W.I.P)',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
const logStats = await LogStats.findOne({where: {guild: message.guild.id}});
|
||||||
|
const ownerID = this.client.ownerID;
|
||||||
|
|
||||||
|
if (!logStats) {
|
||||||
|
const body = {guild: message.guild.id, channel: message.channel.id};
|
||||||
|
await LogStats.create(body);
|
||||||
|
return message.channel.send('Logging has been enabled on this channel');
|
||||||
|
} else if (logStats.get('ownerID') == message.author.id || message.member.hasPermission('ADMINISTRATOR') || message.author.id == ownerID) {
|
||||||
|
message.channel.send('The log channel is already setup, do you want to delete it? y/n');
|
||||||
|
const filter = m => m.content && m.author.id == message.author.id;
|
||||||
|
message.channel.awaitMessages(filter, {time: 5000, max: 1, errors: ['time'] })
|
||||||
|
.then(async messages => {
|
||||||
|
let messageContent = messages.map(messages => messages.content.toLowerCase());
|
||||||
|
if (messageContent[0] === 'y' || messageContent[0] === 'yes') {
|
||||||
|
await LogStats.destroy({where: {guild: message.guild.id}});
|
||||||
|
return message.channel.send('Log channel has been disabled!');
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Not updating.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Took too long to answer. didin\'t change anything.');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return message.channel.send(`You are not the owner of this tag, if you think it is problematic ask an admin to remove it by doing ${this.client.commandHandler.prefix[0]}tag ${args.trigger} --remove`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = logCommand;
|
34
commands/admin/prune.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class PruneCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('Prune', {
|
||||||
|
aliases: ['Prune', 'clean', 'purge', 'clear'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'amount',
|
||||||
|
prompt: {
|
||||||
|
start: 'How many message should i delete?',
|
||||||
|
},
|
||||||
|
type: 'integer'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['MANAGE_MESSAGES', 'SEND_MESSAGES'],
|
||||||
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Bulk delete messages',
|
||||||
|
usage: '[amount]',
|
||||||
|
examples: ['50']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message,args) {
|
||||||
|
if (args.amount >= 100) return;
|
||||||
|
message.channel.bulkDelete(args.amount + 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PruneCommand;
|
|
@ -1,62 +1,45 @@
|
||||||
import { SlashCommandBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, PermissionFlagsBits } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import db from '../../models/index.js';
|
const quotationStat = require('../../models').quotationStat;
|
||||||
|
|
||||||
export default {
|
class quotationCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('quotation')
|
super('quotation', {
|
||||||
.setDescription('Enable or disable quotations')
|
aliases: ['quotation'],
|
||||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
async execute(interaction, args, client) {
|
args: [
|
||||||
const quotationstat = await db.quotationStat.findOne({ where: { serverID: interaction.guild.id } });
|
{
|
||||||
|
id: 'stat',
|
||||||
if (!quotationstat) {
|
type: 'string',
|
||||||
const body = { serverID: interaction.guild.id, stat: 'enable' };
|
prompt: {
|
||||||
await db.quotationStat.create(body);
|
start: 'Do you want to **enable** or **disable** quotation?',
|
||||||
return await interaction.reply({ content: 'Quotation has been enabled.', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`yes${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Yes')
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`no${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('No')
|
|
||||||
.setStyle(ButtonStyle.Danger),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (quotationstat.stat === 'enable') {
|
|
||||||
await interaction.reply({ content: 'Quotation is already enabled, do you wish to disable it?', components: [row], ephemeral: true });
|
|
||||||
}
|
}
|
||||||
else {
|
],
|
||||||
const body = { serverID: interaction.guild.id, stat: 'enable' };
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
await db.autoresponseStat.update(body, { where: { serverID: interaction.guild.id } });
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
return interaction.editReply({ content: 'Quotation has been enabled.', ephemeral: true });
|
channel: 'guild',
|
||||||
}
|
description: {
|
||||||
|
content: 'enable/disable quotation',
|
||||||
return listenButton(client, interaction, interaction.user);
|
usage: '[enable/disable]',
|
||||||
},
|
examples: ['enable']
|
||||||
};
|
|
||||||
|
|
||||||
async function listenButton(client, interaction, user = interaction.user, originalId = interaction.id) {
|
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
|
||||||
if (user !== interactionMenu.user) return listenButton(client, interaction, user, originalId);
|
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `yes${interaction.user.id}${originalId}`) {
|
|
||||||
await db.quotationStat.destroy({ where: { serverID: interaction.guild.id } });
|
|
||||||
return interaction.editReply({ content: 'Quotation has been disabled.', ephemeral: true });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply({ content: 'Nothing has been changed.', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (args.stat.toLowerCase() == 'enable' || args.stat.toLowerCase() == 'disable') {
|
||||||
|
const quotationstat = await quotationStat.findOne({where: {serverID: message.guild.id}});
|
||||||
|
|
||||||
|
if (!quotationstat) {
|
||||||
|
const body = {serverID: message.guild.id, stat: args.stat};
|
||||||
|
quotationStat.create(body);
|
||||||
|
return message.channel.send(`Quotation has been ${args.stat}d`);
|
||||||
|
} else {
|
||||||
|
const body = {serverID: message.guild.id, stat: args.stat};
|
||||||
|
quotationStat.update(body, {where: {serverID: message.guild.id}});
|
||||||
|
return message.channel.send(`Quotation has been ${args.stat}d`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = quotationCommand;
|
|
@ -1,38 +1,66 @@
|
||||||
import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import fs from 'node:fs';
|
const fs = require('fs');
|
||||||
|
|
||||||
export default {
|
class shameboardCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('shameboard')
|
super('shameboard', {
|
||||||
.setDescription('Set shameboard to the current channel.')
|
aliases: ['shameboard'],
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('emote')
|
|
||||||
.setDescription('The emote that should be used to enter the shameboard.'))
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('count')
|
|
||||||
.setDescription('How many react for it to enter shameboard.'))
|
|
||||||
.addBooleanOption(option =>
|
|
||||||
option.setName('remove')
|
|
||||||
.setDescription('Remove the shameboard')
|
|
||||||
.setRequired(false)),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
userPermissions: [PermissionFlagsBits.ManageChannels],
|
channel: 'guild',
|
||||||
async execute(interaction, args) {
|
userPermissions: ['MANAGE_CHANNELS'],
|
||||||
if (args.remove) {
|
args: [
|
||||||
fs.unlink(`./json/board/shame${interaction.guild.id}.json`, (err) => {
|
{
|
||||||
if (err) {return interaction.reply('There is no shameboard');}
|
id: 'emote',
|
||||||
return interaction.reply('Deleted the shameboard');
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'What emote should be used to enter the shameboard?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
default: '👎',
|
||||||
|
unordered: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'count',
|
||||||
|
prompt: {
|
||||||
|
start: 'How many times should that emote be reacted to enter the shameboard?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
type: 'integer',
|
||||||
|
default: '4',
|
||||||
|
unordered: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'remove',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--remove'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Set shameobard in the current channel. --remove to remove the shameboard',
|
||||||
|
usage: '[emote] [minimum number required to enter shameboard]',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (!args.emote || !args.count) return interaction.reply('You are missing the emote or the count arg!');
|
async exec(message, args) {
|
||||||
fs.writeFile(`./json/board/shame${interaction.guild.id}.json`, `{"shameboard": "${interaction.channel.id}", "emote": "${args.emote}", "count": "${args.count}"}`, (err) => {
|
if (!args.remove) {
|
||||||
|
let shameboardChannel = message.channel.id;
|
||||||
|
|
||||||
|
fs.writeFile(`./board/shame${message.guild.id}.json`, `{"shameboard": "${shameboardChannel}" , "emote": "${args.emote}", "count": "${args.count}"}`, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return interaction.reply(`This channel have been set as the shameboard with ${args.emote} with the minimum of ${args.count}`);
|
return message.channel.send(`This channel have been set as the shameboard with ${args.emote} with the minimum of ${args.count}`);
|
||||||
|
} else {
|
||||||
|
fs.unlink(`./board/shame${message.guild.id}.json`, function (err) {
|
||||||
|
if (err) return message.channel.send('There is no shameboard');
|
||||||
|
return message.channel.send('Deleted the shameboard');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
module.exports = shameboardCommand;
|
65
commands/admin/slowmode.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class SlowmodeCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('Slowmode', {
|
||||||
|
aliases: ['slowmode', 'slow', 'cooldown'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'slowmodeNumber',
|
||||||
|
prompt: {
|
||||||
|
start: 'what do you want the delay to be between each message?',
|
||||||
|
},
|
||||||
|
type: 'integer'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'realtime',
|
||||||
|
prompt: {
|
||||||
|
start: 'For how long should the slowmode last?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
type: 'integer',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['MANAGE_CHANNELS'],
|
||||||
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Put a channel in slowmode',
|
||||||
|
usage: '[1-120 slowmode] [Number of minutes the slowmode stay active]',
|
||||||
|
examples: ['5 60']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message,args) {
|
||||||
|
try {
|
||||||
|
let slowmodeNumber = args.slowmodeNumber;
|
||||||
|
let realtime = args.realtime;
|
||||||
|
|
||||||
|
if (slowmodeNumber > 120)
|
||||||
|
return message.channel.send('Slowmode can only be set to 120 seconds or lower!');
|
||||||
|
|
||||||
|
message.channel.setRateLimitPerUser(slowmodeNumber);
|
||||||
|
|
||||||
|
if (realtime) {
|
||||||
|
let time = 60000 * realtime;
|
||||||
|
message.channel.send(`Slowmode have been set to ${slowmodeNumber} seconds and will end in ${realtime} minutes!`);
|
||||||
|
setTimeout (function (){
|
||||||
|
message.channel.setRateLimitPerUser(0);
|
||||||
|
return message.channel.send('Slowmode is now disabled!');
|
||||||
|
}, time);
|
||||||
|
} else {
|
||||||
|
if (slowmodeNumber == 0)
|
||||||
|
return message.channel.send('Slowmode have been disabled!');
|
||||||
|
return message.channel.send(`Slowmode have been set to ${slowmodeNumber} seconds!`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SlowmodeCommand;
|
|
@ -1,38 +1,64 @@
|
||||||
import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import fs from 'node:fs';
|
const fs = require('fs');
|
||||||
|
|
||||||
export default {
|
class StarBoardCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('starboard')
|
super('starboard', {
|
||||||
.setDescription('Set starboard to the current channel.')
|
aliases: ['starboard'],
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('emote')
|
|
||||||
.setDescription('The emote that should be used to enter the starboard.'))
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('count')
|
|
||||||
.setDescription('How many react for it to enter starboard.'))
|
|
||||||
.addBooleanOption(option =>
|
|
||||||
option.setName('remove')
|
|
||||||
.setDescription('Remove the starboard')
|
|
||||||
.setRequired(false)),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
userPermissions: [PermissionFlagsBits.ManageChannels],
|
channel: 'guild',
|
||||||
async execute(interaction, args) {
|
userPermissions: ['MANAGE_CHANNELS'],
|
||||||
if (args.remove) {
|
args: [
|
||||||
fs.unlink(`./json/board/star${interaction.guild.id}.json`, (err) => {
|
{
|
||||||
if (err) {return interaction.reply('There is no starboard');}
|
id: 'emote',
|
||||||
return interaction.reply('Deleted the starboard');
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'What emote should be used to enter the shameboard?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
default: '👍',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'count',
|
||||||
|
type: 'integer',
|
||||||
|
prompt: {
|
||||||
|
start: 'How many times should that emote be reacted to enter the shameboard?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
default: '4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'remove',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--remove'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Set starboard to the current channel. --remove to remove the starboard',
|
||||||
|
usage: '[emote] [minimum number required to enter starboard]',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (!args.emote || !args.count) return interaction.reply('You are missing the emote or the count arg!');
|
async exec(message, args) {
|
||||||
fs.writeFile(`./json/board/star${interaction.guild.id}.json`, `{"starboard": "${interaction.channel.id}", "emote": "${args.emote}", "count": "${args.count}"}`, (err) => {
|
if (!args.remove) {
|
||||||
|
let starboardChannel = message.channel.id;
|
||||||
|
|
||||||
|
fs.writeFile(`./board/star${message.guild.id}.json`, `{"starboard": "${starboardChannel}", "emote": "${args.emote}", "count": "${args.count}"}`, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return interaction.reply(`This channel have been set as the starboard with ${args.emote} with the minimum of ${args.count}`);
|
return message.channel.send(`This channel have been set as the starboard with ${args.emote} with the minimum of ${args.count}`);
|
||||||
|
} else {
|
||||||
|
fs.unlink(`./board/star${message.guild.id}.json`, function (err) {
|
||||||
|
if (err) return message.channel.send('There is no shameboard');
|
||||||
|
return message.channel.send('Deleted the starboard');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
module.exports = StarBoardCommand;
|
|
@ -1,127 +1,114 @@
|
||||||
import { SlashCommandBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, PermissionFlagsBits, PermissionsBitField } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import os from 'node:os';
|
const Tag = require('../../models').Tag;
|
||||||
import fs from 'node:fs';
|
|
||||||
|
|
||||||
import db from '../../models/index.js';
|
class TagCommand extends Command {
|
||||||
|
constructor() {
|
||||||
const { ownerId } = process.env;
|
super('tag', {
|
||||||
|
aliases: ['tag'],
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('tag')
|
|
||||||
.setDescription('Create custom autoresponse')
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('trigger')
|
|
||||||
.setDescription('The strings that will trigger the tag')
|
|
||||||
.setRequired(false))
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('response')
|
|
||||||
.setDescription('What it will answer back')
|
|
||||||
.setRequired(false))
|
|
||||||
.addBooleanOption(option =>
|
|
||||||
option.setName('remove')
|
|
||||||
.setDescription('(ADMIN ONLY!) Remove the tag')
|
|
||||||
.setRequired(false))
|
|
||||||
.addBooleanOption(option =>
|
|
||||||
option.setName('list')
|
|
||||||
.setDescription('List all the tags for the server')
|
|
||||||
.setRequired(false)),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
userPermissions: [PermissionFlagsBits.ManageChannels],
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
async execute(interaction, args, client) {
|
args: [
|
||||||
await interaction.deferReply();
|
{
|
||||||
|
id: 'trigger',
|
||||||
if (args.list) {
|
type: 'string',
|
||||||
let tagList = await db.Tag.findAll({ attributes: ['trigger', 'response', 'ownerID'], where: { serverID: interaction.guild.id } });
|
},
|
||||||
|
{
|
||||||
if (args.trigger) {
|
id: 'remove',
|
||||||
tagList = await db.Tag.findOne({ attributes: ['trigger', 'response', 'ownerID'], where: { trigger: args.trigger, serverID: interaction.guild.id } });
|
match: 'flag',
|
||||||
|
flag: '--remove'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reset',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--reset'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'response',
|
||||||
|
type: 'string',
|
||||||
|
match: 'rest',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Create custom autoresponse (--remove to delete a tag, --reset to delete EVERY tag on the server) [Click here to see the complete list of "tag"](https://cdn.discordapp.com/attachments/502198809355354133/561043193949585418/unknown.png) (Need "" if the trigger contains spaces)',
|
||||||
|
usage: '[trigger] [response]',
|
||||||
|
examples: ['"do you know da wea" Fuck off dead meme', 'hello Hello [author], how are you today?', 'hello --remove']
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tagList) return interaction.editReply('It looks like the server has no tags.');
|
|
||||||
|
|
||||||
const path = `${os.tmpdir()}/${interaction.guild.id}.json`;
|
|
||||||
fs.writeFile(path, JSON.stringify(tagList, null, 2), function(err) {
|
|
||||||
if (err) return console.error(err);
|
|
||||||
});
|
});
|
||||||
return interaction.editReply({ files: [path] });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag = await db.Tag.findOne({ where: { trigger: args.trigger, serverID: interaction.guild.id } });
|
async exec(message, args) {
|
||||||
|
const tag = await Tag.findOne({where: {trigger: args.trigger, serverID: message.guild.id}});
|
||||||
|
const ownerID = this.client.ownerID;
|
||||||
|
|
||||||
|
if (args.reset) {
|
||||||
|
if (message.member.hasPermission('ADMINISTRATOR')) {
|
||||||
|
message.channel.send('Are you sure you want to delete EVERY tag? There is no way to recover them. y/n');
|
||||||
|
|
||||||
|
const filter = m => m.content && m.author.id == message.author.id;
|
||||||
|
return message.channel.awaitMessages(filter, {time: 5000, max: 1, errors: ['time'] })
|
||||||
|
.then(async messages => {
|
||||||
|
let messageContent = messages.map(messages => messages.content.toLowerCase());
|
||||||
|
if (messageContent[0] === 'y' || messageContent[0] === 'yes') {
|
||||||
|
Tag.destroy({where: {serverID: message.guild.id}});
|
||||||
|
return message.channel.send('Tags have been reset.');
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Not reseting.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Took too long to answer. didin\'t update anything.');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Only person with the `ADMINISTRATOR` rank can reset tags.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (args.remove) {
|
if (args.remove) {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
if (tag.get('ownerID') == interaction.user.id || interaction.member.permissionsIn(interaction.channel).has(PermissionsBitField.Flags.Administrator) || interaction.user.id == ownerId) {
|
if (tag.get('ownerID') == message.author.id || message.member.hasPermission('ADMINISTRATOR') || message.author.id == ownerID) {
|
||||||
db.Tag.destroy({ where: { trigger: args.trigger, serverID: interaction.guild.id } });
|
Tag.destroy({where: {trigger: args.trigger, serverID: message.guild.id}});
|
||||||
return interaction.editReply('successfully deleted the following tag: ' + args.trigger);
|
return message.channel.send('successfully deleted the following tag: ' + args.trigger);
|
||||||
|
} else {
|
||||||
|
return message.channel.send(`You are not the owner of this tag, if you think it is problematic ask an admin to remove it by doing ${this.client.commandHandler.prefix[0]}tag ${args.trigger} --remove`);
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
return interaction.editReply(`You are not the owner of this tag, if you think it is problematic ask a user with the 'Administrator' permission to remove it by doing ${this.client.commandHandler.prefix[0]}tag ${args.trigger} --remove`);
|
return message.channel.send('Did not find the specified tag, are you sure it exist?');
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply('Did not find the specified tag, are you sure it exist?');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.trigger) return interaction.editReply('You need to specify what you want me to respond to.');
|
|
||||||
if (!args.response) return interaction.editReply('You need to specify what you want me to answer with.');
|
if (!args.trigger) return message.channel.send('Please provide a trigger in order to create a tag.');
|
||||||
|
|
||||||
|
if (!args.response) return message.channel.send('Please provide the response for that tag');
|
||||||
|
|
||||||
if (!tag) {
|
if (!tag) {
|
||||||
const body = { trigger: args.trigger, response: args.response, ownerID: interaction.user.id, serverID: interaction.guild.id };
|
const body = {trigger: args.trigger, response: args.response, ownerID: message.author.id, serverID: message.guild.id};
|
||||||
await db.Tag.create(body);
|
await Tag.create(body);
|
||||||
return interaction.editReply(`tag have been set to ${args.trigger} : ${args.response}`);
|
return message.channel.send(`tag have been set to ${args.trigger} : ${args.response}`);
|
||||||
}
|
} else if (tag.get('ownerID') == message.author.id || message.member.hasPermission('ADMINISTRATOR') || message.author.id == ownerID) {
|
||||||
else if (tag.get('ownerID') == interaction.user.id || interaction.member.permissionsIn(interaction.channel).has('ADMINISTRATOR') || interaction.user.id == ownerId) {
|
message.channel.send('This tag already exist, do you want to update it? y/n');
|
||||||
|
const filter = m => m.content && m.author.id == message.author.id;
|
||||||
const row = new ActionRowBuilder()
|
message.channel.awaitMessages(filter, {time: 5000, max: 1, errors: ['time'] })
|
||||||
.addComponents(
|
.then(async messages => {
|
||||||
new ButtonBuilder()
|
let messageContent = messages.map(messages => messages.content.toLowerCase());
|
||||||
.setCustomId(`edit${interaction.user.id}${interaction.id}`)
|
if (messageContent[0] === 'y' || messageContent[0] === 'yes') {
|
||||||
.setLabel('Edit')
|
const body = {trigger: args.trigger, response: args.response, ownerID: message.author.id, serverID: message.guild.id};
|
||||||
.setStyle(ButtonStyle.Primary),
|
await Tag.update(body, {where: {trigger: args.trigger, serverID: message.guild.id}});
|
||||||
)
|
return message.channel.send(`tag have been set to ${args.trigger} : ${args.response}`);
|
||||||
.addComponents(
|
} else {
|
||||||
new ButtonBuilder()
|
return message.channel.send('Not updating.');
|
||||||
.setCustomId(`remove${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Remove')
|
|
||||||
.setStyle(ButtonStyle.Danger),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`nothing${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Do nothing')
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
);
|
|
||||||
|
|
||||||
await interaction.editReply({ content: 'This tag already exist, do you want to update it, remove it or do nothing?', components: [row], ephemeral: true });
|
|
||||||
|
|
||||||
return listenButton(client, interaction, args, interaction.user);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply(`You are not the owner of this tag, if you think it is problematic ask an admin to remove it by doing ${this.client.commandHandler.prefix[0]}tag ${args.trigger} --remove`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async function listenButton(client, interaction, args, user = interaction.user, originalId = interaction.id) {
|
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
|
||||||
if (user !== interactionMenu.user) return listenButton(client, interaction, args, user, originalId);
|
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
await interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `edit${interaction.user.id}${originalId}`) {
|
|
||||||
const body = { trigger: args.trigger, response: args.response, ownerID: interaction.user.id, serverID: interaction.guild.id };
|
|
||||||
db.Tag.update(body, { where: { serverID: interaction.guild.id } });
|
|
||||||
return interaction.editReply({ content: `The tag ${args.trigger} has been set to ${args.response}`, ephemeral: true });
|
|
||||||
}
|
|
||||||
else if (interactionMenu.customId === `remove${interaction.user.id}${originalId}`) {
|
|
||||||
db.Tag.destroy({ where: { trigger: args.trigger, serverID: interaction.guild.id } });
|
|
||||||
return interaction.editReply({ content: `The tag ${args.trigger} has been deleted`, ephemeral: true });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply({ content: 'Nothing has been changed.', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Took too long to answer. didin\'t update anything.');
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
return message.channel.send(`You are not the owner of this tag, if you think it is problematic ask an admin to remove it by doing ${this.client.commandHandler.prefix[0]}tag ${args.trigger} --remove`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TagCommand;
|
40
commands/admin/unban.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class UnbanCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('unban', {
|
||||||
|
aliases: ['unban'],
|
||||||
|
category: 'admin',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'member',
|
||||||
|
type: 'integer',
|
||||||
|
prompt: {
|
||||||
|
start: 'which member do you want to unban?',
|
||||||
|
retry: 'This doesn\'t look like an ID, please try again'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientPermissions: ['BAN_MEMBERS'],
|
||||||
|
userPermissions: ['BAN_MEMBERS'],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'unban users',
|
||||||
|
usage: '[user id]',
|
||||||
|
examples: ['267065637183029248']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
message.guild.members.unban(args.member.toString())
|
||||||
|
.then(() => {
|
||||||
|
return message.reply('user was succesfully unbanned.');
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return message.reply('Could not unban this user, is he banned in the first place?');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = UnbanCommand;
|
|
@ -1,75 +1,74 @@
|
||||||
import { SlashCommandBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, PermissionFlagsBits } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import db from '../../models/index.js';
|
const joinChannel = require('../../models').joinChannel;
|
||||||
|
|
||||||
export default {
|
class welcomeCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('welcome')
|
super('welcome', {
|
||||||
.setDescription('Set a join message')
|
aliases: ['welcome', 'join'],
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('message')
|
|
||||||
.setDescription('The message you want the bot to say when someone join in the current channel.')),
|
|
||||||
category: 'admin',
|
category: 'admin',
|
||||||
userPermissions: [PermissionFlagsBits.ManageChannels],
|
channel: 'guild',
|
||||||
async execute(interaction, args, client) {
|
userPermissions: ['MANAGE_CHANNELS'],
|
||||||
const join = await db.joinChannel.findOne({ where: { guildID: interaction.guild.id } });
|
args: [
|
||||||
|
{
|
||||||
if (!join && !args.message) {
|
id: 'remove',
|
||||||
return interaction.reply({ content: 'You need a message for me to say anything!', ephemeral: true });
|
match: 'flag',
|
||||||
}
|
flag: '--remove'
|
||||||
else if (!join) {
|
|
||||||
const body = { guildID: interaction.guild.id, channelID: interaction.channel.id, message: args.message };
|
|
||||||
await db.joinChannel.create(body);
|
|
||||||
return interaction.reply({ content: `The join message have been set with ${args.message}`, ephemeral: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`edit${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Edit')
|
|
||||||
.setStyle(ButtonStyle.Primary),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`remove${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Remove')
|
|
||||||
.setStyle(ButtonStyle.Danger),
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`nothing${interaction.user.id}${interaction.id}`)
|
|
||||||
.setLabel('Do nothing')
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
);
|
|
||||||
|
|
||||||
await interaction.reply({ content: 'The server already has a message set, do you want to edit it or remove it?', components: [row], ephemeral: true });
|
|
||||||
|
|
||||||
return listenButton(client, interaction, args, interaction.user);
|
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
id: 'message',
|
||||||
async function listenButton(client, interaction, args, user = interaction.user, originalId = interaction.id) {
|
type: 'string',
|
||||||
client.once('interactionCreate', async (interactionMenu) => {
|
match: 'rest',
|
||||||
if (user !== interactionMenu.user) return listenButton(client, interaction, args, user, originalId);
|
default: 'Welcome [member] to [server]!'
|
||||||
if (!interactionMenu.isButton()) return;
|
|
||||||
|
|
||||||
await interactionMenu.update({ components: [] });
|
|
||||||
|
|
||||||
if (interactionMenu.customId === `edit${interaction.user.id}${originalId}`) {
|
|
||||||
if (!args.message) {
|
|
||||||
return interaction.reply({ content: 'You need to input a message for me to edit!', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
const body = { guildID: interaction.guild.id, channelID: interaction.channel.id, message: args.message };
|
],
|
||||||
await db.joinChannel.update(body, { where: { guildID: interaction.guild.id } });
|
description: {
|
||||||
return interaction.editReply({ content: `The join message has been set to ${args.message}`, ephemeral: true });
|
content: 'Send a message to the current channel when a person join, you can use [member] to show the member username and [server] to show the name of the server',
|
||||||
}
|
usage: '[welcome message]',
|
||||||
else if (interactionMenu.customId === `remove${interaction.user.id}${originalId}`) {
|
examples: ['everyone welcome [adjectives] [member] and welcome on [server]']
|
||||||
db.joinChannel.destroy({ where: { guildID: interaction.guild.id, channelID: interaction.channel.id } });
|
|
||||||
return interaction.editReply({ content: 'The join message has been deleted.', ephemeral: true });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.editReply({ content: 'Nothing has been changed.', ephemeral: true });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
const join = await joinChannel.findOne({where: {guildID: message.guild.id}});
|
||||||
|
|
||||||
|
if (args.remove) {
|
||||||
|
if (join) {
|
||||||
|
join.destroy({where: {guildID: message.guild.id, channelID: message.channel.id}});
|
||||||
|
return message.channel.send('successfully deleted the join message');
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Did not find the a join message, are you sure you have one setup?');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.message) {
|
||||||
|
return message.channel.send('Please provide a message');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!join) {
|
||||||
|
const body = {guildID: message.guild.id, channelID: message.channel.id, message: args.message};
|
||||||
|
await joinChannel.create(body);
|
||||||
|
return message.channel.send(`The join message have been set with ${args.message}`);
|
||||||
|
} else {
|
||||||
|
message.channel.send('The server already have a join message, do you want to replace it? y/n');
|
||||||
|
const filter = m => m.content && m.author.id == message.author.id;
|
||||||
|
message.channel.awaitMessages(filter, {time: 5000, max: 1, errors: ['time'] })
|
||||||
|
.then(async messages => {
|
||||||
|
let messageContent = messages.map(messages => messages.content);
|
||||||
|
if (messageContent[0] === 'y' || messageContent[0] === 'yes') {
|
||||||
|
const body = {guildID: message.guild.id, channelID: message.channel.id, message: args.message};
|
||||||
|
await joinChannel.update(body, {where: {guildID: message.guild.id}});
|
||||||
|
return message.channel.send(`The join message have been set with ${args.message}`);
|
||||||
|
} else {
|
||||||
|
return message.channel.send('Not updating.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Took too long to answer. didin\'t update anything.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = welcomeCommand;
|
68
commands/admin/whitelistword.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const whitelistWord = require('../../models').whitelistWord;
|
||||||
|
|
||||||
|
class whitelistWordCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('whitelistWord', {
|
||||||
|
aliases: ['whitelistWord', 'unwhitelistword', 'whitelist', 'unwhitelist'],
|
||||||
|
category: 'admin',
|
||||||
|
userPermissions: ['MANAGE_MESSAGES'],
|
||||||
|
clientPermissions: ['MANAGE_MESSAGES', 'SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'word',
|
||||||
|
type: 'string',
|
||||||
|
match: 'rest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'remove',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--remove'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'removeall',
|
||||||
|
match: 'flag',
|
||||||
|
flag: '--removeall'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Whitelist word so it is not affected by the banned word, unwhitelistword alias and --removeaall to remove every banned whitelisted word',
|
||||||
|
usage: '[word to whitelist]',
|
||||||
|
examples: ['sexuality']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (!args.word) args.word = '';
|
||||||
|
args.word = args.word.replace(/[\u0250-\ue007]/g, '');
|
||||||
|
const WhitelistWord = await whitelistWord.findOne({where: {word: args.word.toLowerCase(), serverID: message.guild.id}});
|
||||||
|
|
||||||
|
if (message.util.parsed.alias == 'unwhitelistword' || message.util.parsed.alias == 'unwhitelist' || args.remove || args.removeall) {
|
||||||
|
if (args.removeall) {
|
||||||
|
whitelistWord.destroy({where: {serverID: message.guild.id}});
|
||||||
|
return message.channel.send('The whitelisted words has been reset.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WhitelistWord) {
|
||||||
|
whitelistWord.destroy({where: {word: args.word.toLowerCase(), serverID: message.guild.id}});
|
||||||
|
return message.channel.send(`The word ${args.word.toLowerCase()} is no longer whitelisted`);
|
||||||
|
} else {
|
||||||
|
return message.channel.send('There was no word to unwhitelist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.word) return message.channel.send('Please specify a word to whiteliste!');
|
||||||
|
|
||||||
|
if (!WhitelistWord) {
|
||||||
|
const body = {word: args.word.toLowerCase(), serverID: message.guild.id};
|
||||||
|
await whitelistWord.create(body);
|
||||||
|
return message.channel.send(`The word ${args.word.toLowerCase()} has been whitelisted`);
|
||||||
|
} else {
|
||||||
|
message.channel.send('This word is already whitelisted');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = whitelistWordCommand;
|
|
@ -1,42 +1,48 @@
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import { EmbedBuilder } from 'discord.js';
|
const fetch = require('node-fetch');
|
||||||
import TurndownService from 'turndown';
|
const boards = require('4chan-boards');
|
||||||
const turndown = new TurndownService();
|
const Turndown = require('turndown');
|
||||||
import fetch from 'node-fetch';
|
let turndown = new Turndown();
|
||||||
|
|
||||||
import fourChan from '../../json/4chan.json' with {type: 'json'};
|
class FourchanCommand extends Command {
|
||||||
|
constructor() {
|
||||||
export default {
|
super('4chan', {
|
||||||
data: new SlashCommandBuilder()
|
aliases: ['4chan'],
|
||||||
.setName('4chan')
|
clientPermissions: ['EMBED_LINKS', 'SEND_MESSAGES'],
|
||||||
.setDescription('Send random images from a 4chan board of your choosing!')
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('board')
|
|
||||||
.setDescription('The board you wish to see')
|
|
||||||
.setRequired(true)),
|
|
||||||
category: 'fun',
|
category: 'fun',
|
||||||
async execute(interaction, args) {
|
|
||||||
let board = args.board;
|
|
||||||
|
|
||||||
if (fourChan[board] == undefined) {
|
args: [
|
||||||
return interaction.reply({ content: 'Uh oh! The board you are looking for does not exist? You think this is a mistake? Please send a feedback telling me so!', ephemeral: true });
|
{
|
||||||
|
id: 'board',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Which board do you want to browse?',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Send random images from a 4chan board of your choosing!',
|
||||||
|
usage: '[board]',
|
||||||
|
examples: ['vg']
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fourChan[board].nsfw && !interaction.channel.nsfw) {
|
async exec(message, args) {
|
||||||
return interaction.reply({ content: 'Uh oh! This is a NSFW board! Try again in a NSFW channel!', ephemeral: true });
|
if (boards.getType(args.board) === boards.NSFW && !message.channel.nsfw) return message.channel.send('Sorry, this board only works in nsfw channels!');
|
||||||
}
|
|
||||||
await interaction.deferReply({ ephemeral: false });
|
if (!args.board) return;
|
||||||
|
args.board = args.board.replace(/\//g, '');
|
||||||
|
|
||||||
board = board.replace(/\//g, '');
|
|
||||||
let i = Math.floor((Math.random() * 5) + 1);
|
let i = Math.floor((Math.random() * 5) + 1);
|
||||||
|
|
||||||
|
|
||||||
fetch(`https://a.4cdn.org/${board}/${i}.json`).then((response) => {
|
fetch(`https://a.4cdn.org/${args.board}/${i}.json`).then((response) => {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (!response.threads) {
|
if (!response.threads)
|
||||||
return interaction.editReply('Not a valid board! Try again!');
|
return message.channel.send('Not a valid board! Try again!');
|
||||||
}
|
|
||||||
|
|
||||||
i = Math.floor((Math.random() * response.threads.length) + 1);
|
i = Math.floor((Math.random() * response.threads.length) + 1);
|
||||||
|
|
||||||
|
@ -52,10 +58,8 @@ export default {
|
||||||
|
|
||||||
let title = response.threads[i].posts[0].sub;
|
let title = response.threads[i].posts[0].sub;
|
||||||
let description = response.threads[i].posts[0].com;
|
let description = response.threads[i].posts[0].com;
|
||||||
let boardName = fourChan[board].title;
|
let boardName = boards.getName(args.board);
|
||||||
if (boardName == undefined) {
|
if (boardName == undefined) boardName = args.board;
|
||||||
boardName = board;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If title or description is undefined, change it to "no title/description"
|
// If title or description is undefined, change it to "no title/description"
|
||||||
if (!description) {
|
if (!description) {
|
||||||
|
@ -66,28 +70,28 @@ export default {
|
||||||
title = 'No title';
|
title = 'No title';
|
||||||
}
|
}
|
||||||
|
|
||||||
const FourchanEmbed = new EmbedBuilder()
|
const FourchanEmbed = this.client.util.embed()
|
||||||
.setColor(interaction.member ? interaction.member.displayHexColor : 'Navy')
|
.setColor(message.member ? message.member.displayHexColor : 'NAVY')
|
||||||
.setTitle(turndown.turndown(title))
|
.setTitle(turndown.turndown(title))
|
||||||
.setDescription(turndown.turndown(description))
|
.setDescription(turndown.turndown(description))
|
||||||
.setImage(`https://i.4cdn.org/${board}/${response.threads[i].posts[0].tim}${response.threads[i].posts[0].ext}`)
|
.setImage(`https://i.4cdn.org/${args.board}/${response.threads[i].posts[0].tim}${response.threads[i].posts[0].ext}`)
|
||||||
.setURL(`https://boards.4chan.org/${board}/thread/${response.threads[i].posts[0].no}/${response.threads[i].posts[0].semantic_url}`)
|
.setURL(`https://boards.4chan.org/${args.board}/thread/${response.threads[i].posts[0].no}/${response.threads[i].posts[0].semantic_url}`)
|
||||||
.setFooter({ text: `${boardName} | ${response.threads[i].posts[0].name} | ${response.threads[i].posts[0].no} | ${response.threads[i].posts[0].now}` });
|
.setFooter(`${boardName} | ${response.threads[i].posts[0].name} | ${response.threads[i].posts[0].no} | ${response.threads[i].posts[0].now}`);
|
||||||
|
|
||||||
// If file type dosen't work on embed, send it as a link
|
// If file type dosen't work on embed, send it as a link
|
||||||
if (response.threads[i].posts[0].ext == '.webm' || response.threads[i].posts[0].ext == '.pdf' || response.threads[i].posts[0].ext == '.swf') {
|
if (response.threads[i].posts[0].ext == '.webm' || response.threads[i].posts[0].ext == '.pdf' || response.threads[i].posts[0].ext == '.swf') {
|
||||||
interaction.editReply({ embeds: [FourchanEmbed] });
|
message.channel.send(FourchanEmbed);
|
||||||
interaction.followUp(`https://i.4cdn.org/${board}/${response.threads[i].posts[0].tim}${response.threads[i].posts[0].ext}`);
|
message.channel.send(`https://i.4cdn.org/${args.board}/${response.threads[i].posts[0].tim}${response.threads[i].posts[0].ext}`);
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
message.channel.send(FourchanEmbed);
|
||||||
interaction.editReply({ embeds: [FourchanEmbed] });
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err.type == 'invalid-json') return interaction.editReply('Could not find the board! Try again!');
|
if (err.type == 'invalid-json') return message.channel.send('Could not find the board! Try again!');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return interaction.editReply('Uh-oh, an error has occurred! Try again! If this keeps happening, tell the developers!');
|
return message.channel.send('Uh-oh, an error has occurred! Try again! If this keeps happening, tell the developers!');
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
module.exports = FourchanCommand;
|
58
commands/fun/asciify.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const attachment = require('../../utils/attachment');
|
||||||
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const asciify = require('asciify-image');
|
||||||
|
|
||||||
|
let options = {
|
||||||
|
fit: 'box',
|
||||||
|
width: 200,
|
||||||
|
height: 50,
|
||||||
|
color: false
|
||||||
|
};
|
||||||
|
|
||||||
|
class asciifyCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('asciify', {
|
||||||
|
aliases: ['asciify'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'url',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
cooldown: 600000,
|
||||||
|
ratelimit: 2,
|
||||||
|
description: {
|
||||||
|
content: 'Transform your image into ASCII! (This can be a bit spammy, so be careful!)',
|
||||||
|
usage: '[image in attachment]',
|
||||||
|
examples: ['image in attachment']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (args.link)
|
||||||
|
url = args.link.href;
|
||||||
|
else
|
||||||
|
url = await attachment(message);
|
||||||
|
|
||||||
|
return asciify(url, options, function (err, asciified) {
|
||||||
|
if (err) throw err;
|
||||||
|
// Print to console
|
||||||
|
fs.writeFile(`${os.tmpdir()}/${message.id}ascii.txt`, asciified, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.channel.send({files: [`${os.tmpdir()}/${message.id}ascii.txt`]});
|
||||||
|
});
|
||||||
|
//return message.channel.send(asciified, { split: true, code: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = asciifyCommand;
|
|
@ -1,60 +1,91 @@
|
||||||
/* TODO
|
const { Command } = require('discord-akairo');
|
||||||
*
|
const attachment = require('../../utils/attachment');
|
||||||
* Merge with commands/fun/image2audio.js
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
*
|
const fetch = require('node-fetch');
|
||||||
*/
|
const fs = require('fs');
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
const os = require('os');
|
||||||
import fs from 'node:fs';
|
|
||||||
import os from 'node:os';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
import util from 'node:util';
|
|
||||||
import stream from 'node:stream';
|
|
||||||
import utils from '../../utils/videos.js';
|
|
||||||
|
|
||||||
export default {
|
class audio2imageCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('audio2image')
|
super('audio2image', {
|
||||||
.setDescription('Transform an audio file into an image.')
|
aliases: ['audio2image', 'a2i'],
|
||||||
.addAttachmentOption(option =>
|
|
||||||
option.setName('audio')
|
|
||||||
.setDescription('The audio that will become image.')
|
|
||||||
.setRequired(true)),
|
|
||||||
category: 'fun',
|
category: 'fun',
|
||||||
alias: ['a2i'],
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
async execute(interaction, args) {
|
args: [
|
||||||
if (!args.audio) return interaction.reply('Please attach an image with your message.');
|
{
|
||||||
|
id: 'video_size',
|
||||||
await interaction.deferReply();
|
match: 'option',
|
||||||
|
flag: '--size',
|
||||||
ifExistDelete(`${os.tmpdir()}/${args.audio.name}`);
|
default: '640x480'
|
||||||
ifExistDelete(`${os.tmpdir()}/${args.audio.name}.png`);
|
|
||||||
ifExistDelete(`${os.tmpdir()}/${args.audio.name}.sw`);
|
|
||||||
ifExistDelete(`${os.tmpdir()}/${args.audio.name}.mp3`);
|
|
||||||
|
|
||||||
const streamPipeline = util.promisify(stream.pipeline);
|
|
||||||
const res = await fetch(args.audio.url);
|
|
||||||
if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.');
|
|
||||||
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${args.audio.name}`));
|
|
||||||
|
|
||||||
await utils.ffmpeg(['-i', `${os.tmpdir()}/${args.audio.name}`, '-sample_rate', '44100', '-ac', '1', '-f', 's16le', '-acodec', 'pcm_s16le', `${os.tmpdir()}/${args.audio.name}.sw`]);
|
|
||||||
await utils.ffmpeg(['-pixel_format', 'rgb24', '-video_size', '128x128', '-f', 'rawvideo', '-i', `${os.tmpdir()}/${args.audio.name}.sw`, '-frames:v', '1', `${os.tmpdir()}/${args.audio.name}.png`]);
|
|
||||||
|
|
||||||
const file = fs.statSync(`${os.tmpdir()}/${args.audio.name}.png`);
|
|
||||||
const fileSize = (file.size / 1000000.0).toFixed(2);
|
|
||||||
|
|
||||||
if (fileSize > await utils.getMaxFileSize(interaction.guild)) return interaction.editReply('error');
|
|
||||||
interaction.editReply({ content: `Image file is ${fileSize} MB` });
|
|
||||||
return interaction.followUp({ files: [`${os.tmpdir()}/${args.audio.name}.png`] });
|
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
id: 'link',
|
||||||
async function ifExistDelete(path) {
|
type: 'url',
|
||||||
if (fs.existsSync(path)) {
|
}
|
||||||
fs.rm(path, (err) => {
|
],
|
||||||
console.log('deleted');
|
description: {
|
||||||
if (err) {
|
content: 'Transform an audio file into an image.Use --size (a number) to get a bigger image! (NOTE: bigger image might fail, so be careful!)',
|
||||||
return;
|
usage: '[link to audio] [--size anumber]',
|
||||||
|
examples: ['https://cdn.discordapp.com/attachments/532987690145021982/682654351772221480/jeff.wav (optional) --size 1920x1080']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (args.link)
|
||||||
|
url = args.link.href;
|
||||||
|
else
|
||||||
|
url = await attachment(message);
|
||||||
|
|
||||||
|
let loadingmsg = await message.channel.send('Processing <a:loadingmin:527579785212329984>');
|
||||||
|
|
||||||
|
if (!url) return message.channel.send('Please attach an audio file or use an url');
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(res => {
|
||||||
|
const dest = fs.createWriteStream(`${os.tmpdir()}/${message.id}`);
|
||||||
|
res.body.pipe(dest);
|
||||||
|
dest.on('finish', () => {
|
||||||
|
ffmpeg(`${os.tmpdir()}/${message.id}`) // Convert to raw pcm
|
||||||
|
.audioBitrate(44100)
|
||||||
|
.audioChannels(1)
|
||||||
|
.format('s16le')
|
||||||
|
.audioCodec('pcm_s16le')
|
||||||
|
.output(`${os.tmpdir()}/${message.id}1.sw`)
|
||||||
|
.on('error', (err, stdout, stderr) => {
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Uh oh, an error has occurred!');
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
ffmpeg()
|
||||||
|
.input(`${os.tmpdir()}/${message.id}1.sw`)
|
||||||
|
.inputOption('-pixel_format rgb24')
|
||||||
|
.inputOption(`-video_size ${args.video_size}`)
|
||||||
|
.inputFormat('rawvideo')
|
||||||
|
.frames('1')
|
||||||
|
.output(`${os.tmpdir()}/a2i${message.id}.png`)
|
||||||
|
.on('error', (err, stdout, stderr) => {
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Uh oh, an error has occurred! The image size is most likely bigger than the content! Try again!');
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
console.log('finished');
|
||||||
|
loadingmsg.delete();
|
||||||
|
let file = fs.statSync(`${os.tmpdir()}/a2i${message.id}.png`);
|
||||||
|
let fileSize = (file.size / 1000000.0).toFixed(2);
|
||||||
|
return message.channel.send(`Image is ${fileSize} MB for ${args.video_size} resolution`, {files: [`${os.tmpdir()}/a2i${message.id}.png`]})
|
||||||
|
.catch(() => {
|
||||||
|
return message.channel.send(`End result is too big to fit on discord! File is ${fileSize} MB! Unless it's GB or even TB, in which case that is a huge image!`); });
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = audio2imageCommand;
|
55
commands/fun/cleverbot.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const cleverbot = require('cleverbot-free');
|
||||||
|
let conversation = {};
|
||||||
|
|
||||||
|
class CleverBotCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('CleverBot', {
|
||||||
|
aliases: ['CleverBot', 'cb'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'message',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'What do you want to say to cleverbot?'
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Talk to cleverbot!',
|
||||||
|
usage: '[message]',
|
||||||
|
examples: ['Hello']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let loadingmsg = await message.reply('Processing! <a:loadingmin:527579785212329984>');
|
||||||
|
if (!conversation[message.guild.id]) conversation[message.guild.id] = [];
|
||||||
|
|
||||||
|
if (!conversation[0]) {
|
||||||
|
cleverbot(args.message).then(response => {
|
||||||
|
conversation[message.guild.id].push(args.message);
|
||||||
|
conversation[message.guild.id].push(response);
|
||||||
|
return message.reply(response)
|
||||||
|
.then(() => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cleverbot(args.message, conversation[message.guild.id]).then(response => {
|
||||||
|
conversation[message.guild.id].push(args.message);
|
||||||
|
conversation[message.guild.id].push(response);
|
||||||
|
return message.reply(response)
|
||||||
|
.then(() => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(conversation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = CleverBotCommand;
|
95
commands/fun/curses.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const path = require('path');
|
||||||
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const { Buffer } = require('buffer');
|
||||||
|
const attachment = require('../../utils/attachment');
|
||||||
|
const downloader = require('../../utils/download');
|
||||||
|
|
||||||
|
class cursesCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('curses', {
|
||||||
|
aliases: ['curses', 'curse'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'url',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'webm',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--webm']
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Mess with video length. webm = expanding length and mp4 = very long length',
|
||||||
|
usage: '[link or attachment]',
|
||||||
|
examples: ['https://www.youtube.com/watch?v=QLCPgZ51poU']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let replaceAt = function(string, index, replacement) {
|
||||||
|
return string.substr(0, index) + replacement + string.substr(index + replacement.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
let link;
|
||||||
|
if (args.link)
|
||||||
|
link = args.link.href;
|
||||||
|
else
|
||||||
|
link = await attachment(message);
|
||||||
|
|
||||||
|
if (!link) return message.channel.send('Please specify the URL of the video you want to curse.');
|
||||||
|
|
||||||
|
let ext = path.extname(link.toLowerCase());
|
||||||
|
console.log(ext);
|
||||||
|
if (ext !== '.webm' && ext !== '.mp4')
|
||||||
|
ext = '.mp4';
|
||||||
|
|
||||||
|
|
||||||
|
if (args.webm) ext = '.webm';
|
||||||
|
|
||||||
|
let loadingmsg = await message.channel.send('Processing <a:loadingmin:527579785212329984>');
|
||||||
|
downloader(link, [`--format=${ext.replace('.', '')}`], `${os.tmpdir()}/${message.id}${ext}`)
|
||||||
|
.on('error', async err => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send(err, { code: true });
|
||||||
|
})
|
||||||
|
.on('end', output => {
|
||||||
|
let file = fs.readFileSync(output).toString('hex');
|
||||||
|
|
||||||
|
let searchHex = '6d766864';
|
||||||
|
let replaceHex = '0000180FFFFFF7F';
|
||||||
|
let skipByte = 34;
|
||||||
|
|
||||||
|
let endResult;
|
||||||
|
|
||||||
|
if (ext === '.webm') {
|
||||||
|
searchHex = '2ad7b1';
|
||||||
|
replaceHex = '42FFB060';
|
||||||
|
skipByte = 8;
|
||||||
|
|
||||||
|
endResult = replaceAt(file, file.indexOf(searchHex) + file.substring(file.indexOf(searchHex)).indexOf('4489') + skipByte, replaceHex);
|
||||||
|
} else {
|
||||||
|
endResult = replaceAt(file, file.indexOf(searchHex) + skipByte, replaceHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(`${os.tmpdir()}/cursed${message.id}${ext}`, Buffer.from(endResult, 'hex'));
|
||||||
|
message.delete();
|
||||||
|
return message.channel.send(`Cursed by ${message.author}`, {files: [`${os.tmpdir()}/cursed${message.id}${ext}`]})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Video is too big! try again with something smaller');
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = cursesCommand;
|
29
commands/fun/doesntexist.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const fs = require('fs');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
class dosentexistCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('dosentexist', {
|
||||||
|
aliases: ['doesntexist', 'thispersondoesnotexist', 'de'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
description: {
|
||||||
|
content: 'Send images from thispersondoesnotexist.com!',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message) {
|
||||||
|
fetch('https://thispersondoesnotexist.com/image')
|
||||||
|
.then(res => {
|
||||||
|
const dest = fs.createWriteStream('./asset/img/de.png');
|
||||||
|
res.body.pipe(dest);
|
||||||
|
dest.on('finish', () => {
|
||||||
|
return message.reply({files: ['./asset/img/de.png']});
|
||||||
|
});
|
||||||
|
}); }
|
||||||
|
}
|
||||||
|
module.exports = dosentexistCommand;
|
25
commands/fun/explosm.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const extract = require('meta-extractor');
|
||||||
|
|
||||||
|
class explosmCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('explosm', {
|
||||||
|
aliases: ['explosm', 'rcg'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
description: {
|
||||||
|
content: 'Comic randomly generated from http://explosm.net/rcg',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message) {
|
||||||
|
extract({ uri: 'http://explosm.net/rcg' }, (err, res) => {
|
||||||
|
return message.reply({files: [res.ogImage]});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
module.exports = explosmCommand;
|
76
commands/fun/fakebot.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class fakebotCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('fakebot', {
|
||||||
|
aliases: ['fakebot', 'fakeuser', 'fakemember'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['MANAGE_WEBHOOKS'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'user',
|
||||||
|
type: 'user',
|
||||||
|
prompt: {
|
||||||
|
start: 'Who should i fake?',
|
||||||
|
retry: 'Didn\'t find any user named like that, please say the name again.'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'message',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'What message should i send?',
|
||||||
|
},
|
||||||
|
match: 'rest',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
channel: 'guild',
|
||||||
|
description: {
|
||||||
|
content: 'Fake a bot/user with webhook',
|
||||||
|
usage: '[user] [message]',
|
||||||
|
examples: ['Supositware#1616 hello!']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let Attachment = (message.attachments).array();
|
||||||
|
let url;
|
||||||
|
let username = args.user.username;
|
||||||
|
let member = message.guild.members.resolve(args.user.id);
|
||||||
|
// Get attachment link
|
||||||
|
if (Attachment[0]) {
|
||||||
|
url = Attachment[0].url;
|
||||||
|
}
|
||||||
|
// Show nickname if user is in guild
|
||||||
|
if (member) {
|
||||||
|
if (member.nickname) {
|
||||||
|
username = member.nickname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message.channel.createWebhook(username, {
|
||||||
|
avatar: args.user.displayAvatarURL(),
|
||||||
|
reason: `Fakebot/user command triggered by: ${message.author.username}`
|
||||||
|
})
|
||||||
|
.then(webhook => {
|
||||||
|
// Have to edit after creation otherwise the picture doesn't get applied
|
||||||
|
webhook.edit({
|
||||||
|
name: username,
|
||||||
|
avatar: args.user.displayAvatarURL(),
|
||||||
|
reason: `Fakebot/user command triggered by: ${message.author.username}`
|
||||||
|
});
|
||||||
|
this.client.fetchWebhook(webhook.id, webhook.token)
|
||||||
|
.then(webhook => {
|
||||||
|
message.delete();
|
||||||
|
|
||||||
|
if (url)
|
||||||
|
webhook.send(args.message, {files: [url]});
|
||||||
|
else
|
||||||
|
webhook.send(args.message);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = fakebotCommand;
|
|
@ -1,49 +0,0 @@
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
|
||||||
import { PermissionFlagsBits } from 'discord.js';
|
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('fakeuser')
|
|
||||||
.setDescription('Fake a user with webhooks')
|
|
||||||
.addMentionableOption(option =>
|
|
||||||
option.setName('user')
|
|
||||||
.setDescription('Who do you want to fake?')
|
|
||||||
.setRequired(true))
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('message')
|
|
||||||
.setDescription('What message do you want me to send?')
|
|
||||||
.setRequired(true))
|
|
||||||
.addAttachmentOption(option =>
|
|
||||||
option.setName('image')
|
|
||||||
.setDescription('Optional attachment.')
|
|
||||||
.setRequired(false)),
|
|
||||||
category: 'fun',
|
|
||||||
clientPermissions: [ PermissionFlagsBits.ManageWebhooks ],
|
|
||||||
async execute(interaction, args) {
|
|
||||||
await interaction.deferReply({ ephemeral: true });
|
|
||||||
await interaction.guild.members.fetch();
|
|
||||||
const member = args.user;
|
|
||||||
const message = args.message;
|
|
||||||
const attachment = args.image;
|
|
||||||
const username = member.nickname ? member.nickname : member.user.username;
|
|
||||||
|
|
||||||
const webhook = await interaction.channel.createWebhook({
|
|
||||||
name: username,
|
|
||||||
avatar: member.user.displayAvatarURL(),
|
|
||||||
reason: `Fakebot/user command triggered by: ${interaction.user.username}`,
|
|
||||||
});
|
|
||||||
if (attachment) {
|
|
||||||
await webhook.send({ content: message, files: [attachment] });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await webhook.send({ content: message });
|
|
||||||
}
|
|
||||||
await webhook.delete(`Fakebot/user command triggered by: ${interaction.user.username}`);
|
|
||||||
if (interaction.isMessage) {
|
|
||||||
await interaction.delete();
|
|
||||||
await interaction.deleteReply();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await interaction.editReply({ content: `Faked the user ${member}` });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,93 +0,0 @@
|
||||||
// Tried something to make it work purely with slash commands but it did not work.
|
|
||||||
// The interaction created from a modal lack the showModal function so I can't just call another modal on top
|
|
||||||
// A "solution" for this that I could see is creating a button between each response asking the player to continue or stop which would create a new interaction and (maybe) allow to display a new modal
|
|
||||||
import { SlashCommandBuilder, ActionRowBuilder, TextInputBuilder, SelectMenuBuilder, ModalBuilder, TextInputStyle, InteractionType } from 'discord.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('guess')
|
|
||||||
.setDescription('Guess the number'),
|
|
||||||
category: 'fun',
|
|
||||||
async execute(interaction, args, client) {
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new SelectMenuBuilder()
|
|
||||||
.setCustomId('difficulty')
|
|
||||||
.setPlaceholder('Nothing selected')
|
|
||||||
.addOptions([
|
|
||||||
{ label: 'Easy', value: '100' },
|
|
||||||
{ label: 'Normal', value: '1000' },
|
|
||||||
{ label: 'Hard', value: '10000' },
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
await interaction.reply({ content: 'Which difficulty do you want to play?', ephemeral: true, components: [row] });
|
|
||||||
|
|
||||||
let numberTry = 0;
|
|
||||||
let secretnumber = 0;
|
|
||||||
|
|
||||||
client.on('interactionCreate', async (interactionMenu) => {
|
|
||||||
if (interaction.user !== interactionMenu.user) return;
|
|
||||||
|
|
||||||
const modal = new ModalBuilder()
|
|
||||||
.setCustomId('guessModal')
|
|
||||||
.setTitle('Your guess');
|
|
||||||
|
|
||||||
|
|
||||||
const textRow = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new TextInputBuilder()
|
|
||||||
.setCustomId('input')
|
|
||||||
.setLabel('What is the number?')
|
|
||||||
.setStyle(TextInputStyle.Short),
|
|
||||||
);
|
|
||||||
|
|
||||||
modal.addComponents(textRow);
|
|
||||||
|
|
||||||
async function tryAgain(input) {
|
|
||||||
if (input != secretnumber) {
|
|
||||||
if (input > secretnumber) {
|
|
||||||
modal.setTitle('Its less!\nWhat is the number?');
|
|
||||||
}
|
|
||||||
else if (input < secretnumber) {
|
|
||||||
modal.setTitle('Its more!\nWhat is the number?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await interactionMenu.showModal(modal);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkNumber(input) {
|
|
||||||
numberTry++;
|
|
||||||
if (input.toLowerCase() === 'stop') {
|
|
||||||
return interaction.reply('Ok, let\'s stop playing :(');
|
|
||||||
}
|
|
||||||
else if (input != secretnumber) {
|
|
||||||
console.log('trying again');
|
|
||||||
tryAgain(input);
|
|
||||||
}
|
|
||||||
else if (numberTry > 1) {
|
|
||||||
return interaction.reply(`Congratulations! You won! It took you ${numberTry} turns!`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return interaction.reply('Congratulations! You won! It took you 1 Turn!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interactionMenu.type === InteractionType.ModalSubmit) {
|
|
||||||
if (interactionMenu.customId === 'guessModal') {
|
|
||||||
const input = interactionMenu.fields.getTextInputValue('input');
|
|
||||||
checkNumber(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (interactionMenu.isSelectMenu()) {
|
|
||||||
if (interactionMenu.customId === 'difficulty') {
|
|
||||||
secretnumber = Math.floor((Math.random() * parseInt(interactionMenu.values[0])) + 1);
|
|
||||||
console.log(secretnumber);
|
|
||||||
|
|
||||||
// await interaction.followUp({ content: 'What is the number?', ephemeral: true });
|
|
||||||
await interactionMenu.showModal(modal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
24
commands/fun/ib.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
class InspiroBotCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('InspiroBot', {
|
||||||
|
aliases: ['inspirobot', 'ib'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
description: {
|
||||||
|
content: 'Send images from Inspirobot',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message) {
|
||||||
|
fetch('http://inspirobot.me/api?generate=true')
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(body => message.channel.send({files: [body]}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = InspiroBotCommand;
|
|
@ -1,59 +1,87 @@
|
||||||
/* TODO
|
const { Command } = require('discord-akairo');
|
||||||
*
|
const attachment = require('../../utils/attachment');
|
||||||
* Merge with commands/fun/audio2image.js
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
*
|
const fetch = require('node-fetch');
|
||||||
*/
|
const fs = require('fs');
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
const os = require('os');
|
||||||
import fs from 'node:fs';
|
|
||||||
import os from 'node:os';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
import util from 'node:util';
|
|
||||||
import stream from 'node:stream';
|
|
||||||
import utils from '../../utils/videos.js';
|
|
||||||
|
|
||||||
export default {
|
class image2audioCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('image2audio')
|
super('image2audio', {
|
||||||
.setDescription('Transform an image binary data into audio ( MIGHT BE VERY LOUD )')
|
aliases: ['image2audio', 'i2a'],
|
||||||
.addAttachmentOption(option =>
|
|
||||||
option.setName('img')
|
|
||||||
.setDescription('The image that will become audio. Only tested with png and jpg.')
|
|
||||||
.setRequired(true)),
|
|
||||||
category: 'fun',
|
category: 'fun',
|
||||||
alias: ['i2a'],
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
async execute(interaction, args) {
|
args: [
|
||||||
if (!args.img) return interaction.reply('Please attach an image with your message.');
|
{
|
||||||
|
id: 'link',
|
||||||
await interaction.deferReply();
|
type: 'url',
|
||||||
|
|
||||||
ifExistDelete(`${os.tmpdir()}/${args.img.name}`);
|
|
||||||
ifExistDelete(`${os.tmpdir()}/1${args.img.name}`);
|
|
||||||
ifExistDelete(`${os.tmpdir()}/${args.img.name}.mp3`);
|
|
||||||
|
|
||||||
const streamPipeline = util.promisify(stream.pipeline);
|
|
||||||
const res = await fetch(args.img.url);
|
|
||||||
if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.');
|
|
||||||
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${args.img.name}`));
|
|
||||||
|
|
||||||
await utils.ffmpeg(['-i', `${os.tmpdir()}/${args.img.name}`, '-f', 'rawvideo', `${os.tmpdir()}/1${args.img.name}`]);
|
|
||||||
await utils.ffmpeg(['-sample_rate', '44100', '-ac', '1', '-f', 's16le', '-i', `${os.tmpdir()}/1${args.img.name}`, `${os.tmpdir()}/${args.img.name}.mp3`]);
|
|
||||||
|
|
||||||
const file = fs.statSync(`${os.tmpdir()}/${args.img.name}.mp3`);
|
|
||||||
const fileSize = (file.size / 1000000.0).toFixed(2);
|
|
||||||
|
|
||||||
if (fileSize > await utils.getMaxFileSize(interaction.guild)) return interaction.editReply('error');
|
|
||||||
interaction.editReply({ content: `Audio file is ${fileSize} MB` });
|
|
||||||
return interaction.followUp({ files: [`${os.tmpdir()}/${args.img.name}.mp3`] });
|
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
id: 'wav',
|
||||||
async function ifExistDelete(path) {
|
type: 'flag',
|
||||||
if (fs.existsSync(path)) {
|
flag: '--wav'
|
||||||
fs.rm(path, (err) => {
|
}
|
||||||
console.log('deleted');
|
],
|
||||||
if (err) {
|
description: {
|
||||||
return;
|
content: 'Transform an image binary data into audio ( MIGHT BECOME EAR RAPE ) --wav to get wav output',
|
||||||
|
usage: '[link to image]',
|
||||||
|
examples: ['https://cdn.discordapp.com/attachments/532987690145021982/682694359313022987/a2i682694012309864452.png']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (args.link)
|
||||||
|
url = args.link.href;
|
||||||
|
else
|
||||||
|
url = await attachment(message);
|
||||||
|
|
||||||
|
let loadingmsg = await message.channel.send('Processing <a:loadingmin:527579785212329984>');
|
||||||
|
|
||||||
|
if (!url) return message.channel.send('Please attach an image or use an url');
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(res => {
|
||||||
|
const dest = fs.createWriteStream(`${os.tmpdir()}/${message.id}.png`);
|
||||||
|
res.body.pipe(dest);
|
||||||
|
dest.on('finish', () => {
|
||||||
|
ffmpeg(`${os.tmpdir()}/${message.id}.png`)
|
||||||
|
.format('rawvideo')
|
||||||
|
.output(`${os.tmpdir()}/${message.id}1.png`)
|
||||||
|
.on('error', (err, stdout, stderr) => {
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Uh oh, an error has occurred!');
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
ffmpeg()
|
||||||
|
.audioBitrate(44100)
|
||||||
|
.audioChannels(1)
|
||||||
|
.input(`${os.tmpdir()}/${message.id}1.png`)
|
||||||
|
.inputFormat('s16le')
|
||||||
|
.output(`${os.tmpdir()}/i2a_${message.id}.${args.wav ? 'wav' : 'mp3'}`)
|
||||||
|
.on('error', (err, stdout, stderr) => {
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Uh oh, an error has occurred!');
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
console.log('finished');
|
||||||
|
loadingmsg.delete();
|
||||||
|
let file = fs.statSync(`${os.tmpdir()}/i2a_${message.id}.${args.wav ? 'wav' : 'mp3'}`);
|
||||||
|
let fileSize = (file.size / 1000000.0).toFixed(2);
|
||||||
|
return message.channel.send(`Audio file is ${fileSize} MB`, {files: [`${os.tmpdir()}/i2a_${message.id}.${args.wav ? 'wav' : 'mp3'}`]})
|
||||||
|
.catch(() => {
|
||||||
|
return message.channel.send(`End result is too big to fit on discord! File is ${fileSize} MB`);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = image2audioCommand;
|
34
commands/fun/imgur.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
class ImgurCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('imgur', {
|
||||||
|
aliases: ['imgur', 'badmeme'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'EMBED_LINKS'],
|
||||||
|
description: {
|
||||||
|
content: 'Send some random images from imgur',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message) {
|
||||||
|
fetch('https://api.imgur.com/3/gallery/hot/day?showViral=true&mature=false&perPage=100&album_previews=true', {
|
||||||
|
headers: { 'Authorization': 'Client-ID e4cb6948f80f295' },
|
||||||
|
}).then((response) => {
|
||||||
|
return response.json();
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.success == 'false')
|
||||||
|
return message.channel.send('An error has occurred');
|
||||||
|
|
||||||
|
const i = Math.floor((Math.random() * response.data.length));
|
||||||
|
|
||||||
|
message.channel.send(`**${response.data[i].title}**\n${response.data[i].link}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ImgurCommand;
|
|
@ -1,15 +0,0 @@
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('inspirobot')
|
|
||||||
.setDescription('Get an image from inspirobot'),
|
|
||||||
category: 'fun',
|
|
||||||
alias: ['ib'],
|
|
||||||
async execute(interaction) {
|
|
||||||
fetch('http://inspirobot.me/api?generate=true')
|
|
||||||
.then(res => res.text())
|
|
||||||
.then(body => interaction.reply({ files: [body] }));
|
|
||||||
},
|
|
||||||
};
|
|
133
commands/fun/midify.js
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const attachment = require('../../utils/attachment');
|
||||||
|
const util = require('util');
|
||||||
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
const downloader = require('../../utils/download');
|
||||||
|
const os = require('os');
|
||||||
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
|
|
||||||
|
|
||||||
|
class midifyCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('midify', {
|
||||||
|
aliases: ['midify', 'wav2midi', 'w2m', 'mp32midi', 'm2m', 'sound2midi', 's2m'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'url',
|
||||||
|
match: 'rest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'raw',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--raw']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'noteblock',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--noteblock']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'voice',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--voice']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Transform the audio into midi --raw to get the .mid file',
|
||||||
|
usage: '[link to video/music/whatever you want to be midi]',
|
||||||
|
examples: ['https://www.youtube.com/watch?v=kXYiU_JCYtU']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (args.link)
|
||||||
|
url = args.link.href;
|
||||||
|
else
|
||||||
|
url = await attachment(message);
|
||||||
|
|
||||||
|
let input = `${os.tmpdir()}/${message.id}`;
|
||||||
|
let input2 = `${os.tmpdir()}/${message.id}.wav`;
|
||||||
|
let output = `${os.tmpdir()}/${message.id}.mid`;
|
||||||
|
let output2 = `${os.tmpdir()}/${message.id}.mp3`;
|
||||||
|
|
||||||
|
|
||||||
|
let loadingmsg = await message.channel.send('Processing (this can take some time) <a:loadingmin:527579785212329984>');
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
downloader(url, null, input)
|
||||||
|
.on('error', (err) => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send(err, { code: true });
|
||||||
|
})
|
||||||
|
.on('end', output => {
|
||||||
|
// Convert to wav
|
||||||
|
ffmpeg()
|
||||||
|
.input(output)
|
||||||
|
.output(input2)
|
||||||
|
.on('end', () => {
|
||||||
|
midify();
|
||||||
|
})
|
||||||
|
.on('error', (err, stdout, stderr) => {
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Oh no! an error has occurred during the conversion, are you sure it is a valid file?');
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return message.channel.send('You need a valid video link!');
|
||||||
|
}
|
||||||
|
|
||||||
|
function midify() {
|
||||||
|
// wav to midi
|
||||||
|
exec(`waon -i ${input2} -o ${output}`)
|
||||||
|
.then(() => {
|
||||||
|
|
||||||
|
if (args.raw) {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send({files: [output]})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send('On no! an error just occurred! perhaps the file is too big?');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let option;
|
||||||
|
|
||||||
|
if (args.noteblock) {
|
||||||
|
option = '-c ./asset/timidity/config/noteblock.cfg';
|
||||||
|
} else if (args.voice) {
|
||||||
|
option = '-c ./asset/timidity/config/voice.cfg';
|
||||||
|
}
|
||||||
|
|
||||||
|
// midi to mp3 so we can listen from discord
|
||||||
|
exec(`timidity ${output} ${option} -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k ${output2}`)
|
||||||
|
.then(() => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send({files: [output2]})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send('On no! an error just occurred! perhaps the file is too big?');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Oh no! an error has occurred during the conversion, are you sure it is a valid file?');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send('Oh no! an error has occurred during the conversion, are you sure it is a valid file?');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = midifyCommand;
|
66
commands/fun/petittube.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const { proxy } = require('../../config.json');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
|
||||||
|
class PetitTubeCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('petittube', {
|
||||||
|
aliases: ['petittube', 'pt'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'proxy',
|
||||||
|
match: 'option',
|
||||||
|
flag: ['--proxy'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'listproxy',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--listproxy', '--proxylist']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Fetch a video from https://petittube.com/',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (args.listproxy) {
|
||||||
|
let proxys = [];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
proxy.forEach(proxy => {
|
||||||
|
i++;
|
||||||
|
proxys.push(`[${i}] ${ proxy.hideip ? '[IP HIDDEN]' : proxy.ip.substring(0, proxy.ip.length - 5)} - ${proxy.country}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const Embed = this.client.util.embed()
|
||||||
|
.setColor(message.member ? message.member.displayHexColor : 'NAVY')
|
||||||
|
.setTitle('List of available proxy')
|
||||||
|
.setDescription(proxys.join('\n'))
|
||||||
|
.setFooter('You can help me get more proxy by either donating to me or providing a proxy for me');
|
||||||
|
|
||||||
|
return message.channel.send(Embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch('https://petittube.com/');
|
||||||
|
const body = await response.text();
|
||||||
|
|
||||||
|
const $ = cheerio.load(body);
|
||||||
|
|
||||||
|
const url = $('iframe')[0].attribs.src;
|
||||||
|
|
||||||
|
if (args.proxy) {
|
||||||
|
args.proxy = args.proxy -1;
|
||||||
|
if (!proxy[args.proxy]) args.proxy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.commandHandler.runCommand(message, this.client.commandHandler.findCommand('download'), { link: new URL(url), proxy: args.proxy, spoiler: !message.channel.nsfw, caption: message.channel.nsfw ? '' : 'Video might be NSFW as always, be careful!'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = PetitTubeCommand;
|
|
@ -1,46 +1,61 @@
|
||||||
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import fetch from 'node-fetch';
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
export default {
|
class RedditCommand extends Command {
|
||||||
data: new SlashCommandBuilder()
|
constructor() {
|
||||||
.setName('reddit')
|
super('reddit', {
|
||||||
.setDescription('Send random images from the subreddit you choose')
|
aliases: ['reddit'],
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('subreddit')
|
|
||||||
.setDescription('The subreddit you wish to see')
|
|
||||||
.setRequired(true)),
|
|
||||||
category: 'fun',
|
category: 'fun',
|
||||||
async execute(interaction, args) {
|
clientPermissions: ['SEND_MESSAGES', 'EMBED_LINKS'],
|
||||||
await interaction.deferReply({ ephemeral: false });
|
args: [
|
||||||
const subreddit = args.subreddit;
|
{
|
||||||
fetch('https://www.reddit.com/r/' + subreddit + '.json?limit=100').then((response) => {
|
id: 'sub',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'What subreddit do you want to browse?',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
default: 'random',
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Send random images from the subreddit you choose',
|
||||||
|
usage: '[subreddit]',
|
||||||
|
examples: ['2meirl4meirl']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
//let i = 0;
|
||||||
|
//let a = 0;
|
||||||
|
if (!args.sub)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fetch('https://www.reddit.com/r/' + args.sub + '.json?limit=100').then((response) => {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.error == 404) {
|
console.log(response);
|
||||||
return interaction.editReply('Not a valid subreddit');
|
if (response.error == 404)
|
||||||
}
|
return message.reply('Not a valid subreddit');
|
||||||
if (response.data.dist == 0) {
|
|
||||||
return interaction.editReply('Not a valid subreddit');
|
|
||||||
|
|
||||||
}
|
if (response.data.dist == 0)
|
||||||
const i = Math.floor((Math.random() * response.data.children.length));
|
return message.reply('Not a valid subreddit');
|
||||||
if (response.data.children[i].data.over_18 == true && !interaction.channel.nsfw) {
|
|
||||||
return interaction.editReply('No nsfw');
|
|
||||||
}
|
|
||||||
|
|
||||||
let description = response.data.children[i].data.selftext;
|
let i = Math.floor((Math.random() * response.data.children.length));
|
||||||
if (description === '') {
|
if (response.data.children[i].data.over_18 == true && !message.channel.nsfw)
|
||||||
description = 'No description.';
|
return message.reply('No nsfw');
|
||||||
}
|
const redditEmbed = this.client.util.embed()
|
||||||
const redditEmbed = new EmbedBuilder()
|
.setColor(message.member ? message.member.displayHexColor : 'NAVY')
|
||||||
.setColor(interaction.member ? interaction.member.displayHexColor : 'Navy')
|
|
||||||
.setTitle(response.data.children[i].data.title)
|
.setTitle(response.data.children[i].data.title)
|
||||||
.setDescription(description)
|
.setDescription(response.data.children[i].data.selftext)
|
||||||
.setURL('https://reddit.com' + response.data.children[i].data.permalink)
|
.setURL('https://reddit.com' + response.data.children[i].data.permalink)
|
||||||
.setFooter({ text: `/r/${response.data.children[i].data.subreddit} | ⬆ ${response.data.children[i].data.ups} 🗨 ${response.data.children[i].data.num_comments}` });
|
.setFooter(`/r/${response.data.children[i].data.subreddit} | ⬆ ${response.data.children[i].data.ups} 🗨 ${response.data.children[i].data.num_comments}`);
|
||||||
|
|
||||||
interaction.followUp({ embeds: [redditEmbed] });
|
message.reply(redditEmbed);
|
||||||
interaction.followUp(response.data.children[i].data.url);
|
message.reply(response.data.children[i].data.url);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
module.exports = RedditCommand;
|
47
commands/fun/spb.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const fs = require('fs');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
class spbCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('spb', {
|
||||||
|
aliases: ['spb'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'url',
|
||||||
|
prompt: {
|
||||||
|
start: 'Need a shitpostbot5000 template link!',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Generate a meme from template you send with spb5k (ONLY WORK WITH TEMPLATES)',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (!args.link || !args.link.href.includes('shitpostbot.com/template/')) {
|
||||||
|
return message.reply('Need a Shitpostbot 5000 template link!\nYou can find them here! <https://www.shitpostbot.com/gallery/templates>');
|
||||||
|
}
|
||||||
|
|
||||||
|
let link = args.link.href.replace('template', 'preview');
|
||||||
|
|
||||||
|
fetch(link)
|
||||||
|
.then(res => {
|
||||||
|
const dest = fs.createWriteStream(`${os.tmpdir()}/${message.id}.jpg`);
|
||||||
|
res.body.pipe(dest);
|
||||||
|
dest.on('finish', () => {
|
||||||
|
return message.reply({files: [`${os.tmpdir()}/${message.id}.jpg`]});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = spbCommand;
|
59
commands/fun/tts/dectalk.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const { execFile } = require('child_process');
|
||||||
|
const rand = require('../../../rand.js');
|
||||||
|
|
||||||
|
class dectalkCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('dectalk', {
|
||||||
|
aliases: ['dectalk', 'dec'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'decMessage',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back in dectalk',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Send a wav of what you wrote into .wav with dectalk',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['This command is very epic']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
args.decMessage = rand.random(args.decMessage, message);
|
||||||
|
let output = `${message.id}_dectalk.wav`;
|
||||||
|
let decMessage = '[:phoneme on]' + args.decMessage;
|
||||||
|
let loadingmsg = await message.channel.send('Processing ( this can take some time ) <a:loadingmin:527579785212329984>');
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
execFile('say.exe', ['-w', output, `${decMessage}`], {cwd: './dectalk/'}, (error, stdout, stderr) => {
|
||||||
|
sendMessage(output, error, stdout, stderr);
|
||||||
|
});
|
||||||
|
} else if (process.platform === 'linux' || process.platform === 'darwin') {
|
||||||
|
execFile('wine', ['say.exe', '-w', output, `${decMessage}`], {cwd: './dectalk/'}, (error, stdout, stderr) => {
|
||||||
|
sendMessage(`./dectalk/${output}`, error, stdout, stderr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendMessage(file, error, stdout, stderr) {
|
||||||
|
console.error(stdout);
|
||||||
|
loadingmsg.delete();
|
||||||
|
if (error) {
|
||||||
|
console.error(stderr);
|
||||||
|
console.error(error);
|
||||||
|
return message.channel.send('Oh no! an error has occurred!');
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.channel.send({files: [file]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = dectalkCommand;
|
81
commands/fun/tts/dectalkvc.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const { execFile } = require('child_process');
|
||||||
|
const rand = require('../../../rand.js');
|
||||||
|
|
||||||
|
class dectalkvcCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('dectalkvc', {
|
||||||
|
aliases: ['dectalkvc', 'decvc'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SPEAK'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'decMessage',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back in dectalk',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Repeat what you sent in the voice chat you are currently in',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['This command is very epic']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
args.decMessage = rand.random(args.decMessage, message);
|
||||||
|
let output = `${message.id}_dectalk.wav`;
|
||||||
|
let decMessage = '[:phoneme on] ' + args.decMessage;
|
||||||
|
let loadingmsg = await message.channel.send('Processing ( this can take some time ) <a:loadingmin:527579785212329984>');
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
execFile('say.exe', ['-w', output, `${decMessage}`], {cwd: './dectalk/'}, async (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
loadingmsg.delete();
|
||||||
|
console.error(stdout);
|
||||||
|
console.error(stderr);
|
||||||
|
console.error(error);
|
||||||
|
return message.channel.send('Oh no! an error has occurred!');
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingmsg.delete();
|
||||||
|
playinVC(`./dectalk/${output}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (process.platform === 'linux' || process.platform === 'darwin') {
|
||||||
|
execFile('wine', ['say.exe', '-w', output, `${decMessage}`], {cwd: './dectalk/'}, async (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
loadingmsg.delete();
|
||||||
|
console.error(stdout);
|
||||||
|
console.error(stderr);
|
||||||
|
console.error(error);
|
||||||
|
return message.channel.send('Oh no! an error has occurred!');
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingmsg.delete();
|
||||||
|
playinVC(`./dectalk/${output}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function playinVC(file) {
|
||||||
|
const voiceChannel = message.member.voice.channel;
|
||||||
|
if (!voiceChannel) return message.channel.send('Please enter a voice channel first.');
|
||||||
|
try {
|
||||||
|
const connection = await voiceChannel.join();
|
||||||
|
const dispatcher = connection.play(file);
|
||||||
|
dispatcher.once('finish', () => voiceChannel.leave());
|
||||||
|
dispatcher.once('error', () => voiceChannel.leave());
|
||||||
|
return null;
|
||||||
|
} catch (err) {
|
||||||
|
voiceChannel.leave();
|
||||||
|
return message.reply(`Oh no, an error occurred: \`${err.message}\`.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = dectalkvcCommand;
|
93
commands/fun/tts/sam.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const axios = require('axios');
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const rand = require('../../../rand.js');
|
||||||
|
|
||||||
|
class samCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('sam', {
|
||||||
|
aliases: ['sam'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'samMessage',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back in sam',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Send a mp3 of what you wrote in Microsoft Sam tts, can change speed and pitch with [speed:a number] and [pitch:a number]',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['Here comes the roflcopter soisoisoisoisoi']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
args.samMessage = rand.random(args.samMessage, message);
|
||||||
|
let pitch;
|
||||||
|
if (args.samMessage.includes('[pitch:')) {
|
||||||
|
pitch = args.samMessage.split(/(\[pitch:.*?])/);
|
||||||
|
for (let i = 0, l = pitch.length; i < l; i++) {
|
||||||
|
if (pitch[i].includes('[pitch:')) {
|
||||||
|
pitch = pitch[i].replace('[pitch:', '').slice(0, -1);
|
||||||
|
args.samMessage = args.samMessage.replace(/(\[pitch:.*?])/g, '');
|
||||||
|
i = pitch.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pitch > 200)
|
||||||
|
pitch = 200;
|
||||||
|
else if (pitch < 50)
|
||||||
|
pitch = 50;
|
||||||
|
} else {
|
||||||
|
pitch = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
let speed;
|
||||||
|
if (args.samMessage.includes('[speed:')) {
|
||||||
|
speed = args.samMessage.split(/(\[speed:.*?])/);
|
||||||
|
for (let i = 0, l = speed.length; i < l; i++) {
|
||||||
|
if (speed[i].includes('[speed:')) {
|
||||||
|
speed = speed[i].replace('[speed:', '').slice(0, -1);
|
||||||
|
args.samMessage = args.samMessage.replace(/(\[speed:.*?])/g, '');
|
||||||
|
i = speed.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (speed > 450)
|
||||||
|
speed = 450;
|
||||||
|
else if (speed < 30)
|
||||||
|
speed = 30;
|
||||||
|
} else {
|
||||||
|
speed = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.samMessage = args.samMessage.replace('\n', ' ');
|
||||||
|
args.samMessage = encodeURI(args.samMessage);
|
||||||
|
|
||||||
|
return axios.request({
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
url: `https://tetyys.com/SAPI4/SAPI4?text=${args.samMessage}&voice=Sam&pitch=${pitch}&speed=${speed}`,
|
||||||
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'audio/mpeg',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send(`Uh oh, an error has occurred! please try again later.\n${err}`);
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
const outputFilename = `${os.tmpdir}/${message.id}_sam.wav`;
|
||||||
|
fs.writeFileSync(outputFilename, result.data);
|
||||||
|
return message.channel.send({files: [outputFilename]});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = samCommand;
|
107
commands/fun/tts/samvc.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const axios = require('axios');
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const rand = require('../../../rand.js');
|
||||||
|
|
||||||
|
class samvcCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('samvc', {
|
||||||
|
aliases: ['samvc'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SPEAK'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'samMessage',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back in sam',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Repeat what you said in voice chat with Microsoft Sam tts, can change speed and pitch with [speed:a number] and [pitch:a]',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['Here comes the roflcopter soisoisoisoisoi']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
args.samMessage = rand.random(args.samMessage, message);
|
||||||
|
let pitch;
|
||||||
|
if (args.samMessage.includes('[pitch:')) {
|
||||||
|
pitch = args.samMessage.split(/(\[pitch:.*?])/);
|
||||||
|
for (let i = 0, l = pitch.length; i < l; i++) {
|
||||||
|
if (pitch[i].includes('[pitch:')) {
|
||||||
|
pitch = pitch[i].replace('[pitch:', '').slice(0, -1);
|
||||||
|
args.samMessage = args.samMessage.replace(/(\[pitch:.*?])/g, '');
|
||||||
|
i = pitch.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pitch > 200)
|
||||||
|
pitch = 200;
|
||||||
|
else if (pitch < 50)
|
||||||
|
pitch = 50;
|
||||||
|
} else {
|
||||||
|
pitch = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
let speed;
|
||||||
|
if (args.samMessage.includes('[speed:')) {
|
||||||
|
speed = args.samMessage.split(/(\[speed:.*?])/);
|
||||||
|
for (let i = 0, l = speed.length; i < l; i++) {
|
||||||
|
if (speed[i].includes('[speed:')) {
|
||||||
|
speed = speed[i].replace('[speed:', '').slice(0, -1);
|
||||||
|
args.samMessage = args.samMessage.replace(/(\[speed:.*?])/g, '');
|
||||||
|
i = speed.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (speed > 450)
|
||||||
|
speed = 450;
|
||||||
|
else if (speed < 30)
|
||||||
|
speed = 30;
|
||||||
|
} else {
|
||||||
|
speed = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.samMessage = args.samMessage.replace('\n', ' ');
|
||||||
|
args.samMessage = encodeURI(args.samMessage);
|
||||||
|
|
||||||
|
return axios.request({
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
url: `https://tetyys.com/SAPI4/SAPI4?text=${args.samMessage}&voice=Sam&pitch=${pitch}&speed=${speed}`,
|
||||||
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'audio/mpeg',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send(`Uh oh, an error has occurred! please try again later.\n${err}`);
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(async (result) => {
|
||||||
|
const outputFilename = `${os.tmpdir}/${message.id}_sam.wav`;
|
||||||
|
|
||||||
|
fs.writeFile(outputFilename, result.data, async function(err) {
|
||||||
|
if (err) console.error(err);
|
||||||
|
const voiceChannel = message.member.voice.channel;
|
||||||
|
if (!voiceChannel) return message.channel.send('Please enter a voice channel first.');
|
||||||
|
try {
|
||||||
|
const connection = await voiceChannel.join();
|
||||||
|
const dispatcher = connection.play(outputFilename);
|
||||||
|
dispatcher.once('finish', () => voiceChannel.leave());
|
||||||
|
dispatcher.once('error', () => voiceChannel.leave());
|
||||||
|
return null;
|
||||||
|
} catch (err) {
|
||||||
|
voiceChannel.leave();
|
||||||
|
return message.reply(`Oh no, an error occurred: \`${err.message}\`.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = samvcCommand;
|
70
commands/fun/tts/tts.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const textToSpeech = require('@google-cloud/text-to-speech');
|
||||||
|
const rand = require('../../../rand.js');
|
||||||
|
const gclient = new textToSpeech.TextToSpeechClient();
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
class TtsCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('tts', {
|
||||||
|
aliases: ['tts'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back in Google tts',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Send a mp3 of what you wrote in tts',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['hello']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let text = args.text;
|
||||||
|
let output = `${os.tmpdir()}/${message.id}_tts.mp3`;
|
||||||
|
|
||||||
|
text = rand.random(text, message);
|
||||||
|
|
||||||
|
// Construct the request
|
||||||
|
const request = {
|
||||||
|
input: { text: text },
|
||||||
|
// Select the language and SSML Voice Gender (optional)
|
||||||
|
voice: { languageCode: 'en-US', ssmlGender: 'NEUTRAL' },
|
||||||
|
// Select the type of audio encoding
|
||||||
|
audioConfig: { audioEncoding: 'MP3' },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Performs the Text-to-Speech request
|
||||||
|
gclient.synthesizeSpeech(request, (err, response) => {
|
||||||
|
if (err) {
|
||||||
|
|
||||||
|
console.error('ERROR:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the binary audio content to a local file
|
||||||
|
fs.writeFile(output, response.audioContent, 'binary', err => {
|
||||||
|
if (err) {
|
||||||
|
console.error('ERROR:', err);
|
||||||
|
message.channel.send('An error has occurred, the message is probably too long');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('Audio content written to file: tts.mp3');
|
||||||
|
message.channel.send({ files: [output] });
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = TtsCommand;
|
79
commands/fun/tts/ttsvc.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const textToSpeech = require('@google-cloud/text-to-speech');
|
||||||
|
const rand = require('../../../rand.js');
|
||||||
|
const gclient = new textToSpeech.TextToSpeechClient();
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
class TtsvcCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('ttsvc', {
|
||||||
|
aliases: ['ttsvc'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SPEAK'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back in Google tts',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Say what you wrote in voice channel',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['hello']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let text = args.text;
|
||||||
|
let output = `${os.tmpdir()}/${message.id}_tts.mp3`;
|
||||||
|
|
||||||
|
text = rand.random(text, message);
|
||||||
|
|
||||||
|
// Construct the request
|
||||||
|
const request = {
|
||||||
|
input: { text: text },
|
||||||
|
// Select the language and SSML Voice Gender (optional)
|
||||||
|
voice: { languageCode: 'en-US', ssmlGender: 'NEUTRAL' },
|
||||||
|
// Select the type of audio encoding
|
||||||
|
audioConfig: { audioEncoding: 'MP3' },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Performs the Text-to-Speech request
|
||||||
|
gclient.synthesizeSpeech(request, (err, response) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('ERROR:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the binary audio content to a local file
|
||||||
|
fs.writeFile(output, response.audioContent, 'binary', async err => {
|
||||||
|
if (err) {
|
||||||
|
console.error('ERROR:', err);
|
||||||
|
message.channel.send('An error has occurred, the message is probably too long');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const voiceChannel = message.member.voice.channel;
|
||||||
|
if (!voiceChannel) return message.channel.send('Please enter a voice channel first.');
|
||||||
|
try {
|
||||||
|
const connection = await voiceChannel.join();
|
||||||
|
const dispatcher = connection.play(output);
|
||||||
|
dispatcher.once('finish', () => voiceChannel.leave());
|
||||||
|
dispatcher.once('error', () => voiceChannel.leave());
|
||||||
|
return null;
|
||||||
|
} catch (err) {
|
||||||
|
voiceChannel.leave();
|
||||||
|
return message.reply(`Oh no, an error occurred: \`${err.message}\`.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = TtsvcCommand;
|
|
@ -1,204 +0,0 @@
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
|
||||||
import { EmbedBuilder } from 'discord.js';
|
|
||||||
import { TwitterApi } from 'twitter-api-v2';
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
import os from 'node:os';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import util from 'node:util';
|
|
||||||
import stream from 'node:stream';
|
|
||||||
|
|
||||||
import db from '../../models/index.js';
|
|
||||||
import wordToCensor from '../../json/censor.json' with {type: 'json'};
|
|
||||||
const { twiConsumer, twiConsumerSecret, twiToken, twiTokenSecret, twiChannel, twiLogChannel } = process.env;
|
|
||||||
|
|
||||||
const Blacklists = db.Blacklists;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('tweet')
|
|
||||||
.setDescription('Send tweet from the bot twitter account. Please do not use it for advertisement and keep it english')
|
|
||||||
.addStringOption(option =>
|
|
||||||
option.setName('content')
|
|
||||||
.setDescription('!THIS IS NOT FEEDBACK! The content of the tweet you want to send me.')
|
|
||||||
.setRequired(false))
|
|
||||||
.addAttachmentOption(option =>
|
|
||||||
option.setName('image')
|
|
||||||
.setDescription('Optional attachment (Image only.)')
|
|
||||||
.setRequired(false)),
|
|
||||||
category: 'fun',
|
|
||||||
ratelimit: 3,
|
|
||||||
cooldown: 86400,
|
|
||||||
guildOnly: true,
|
|
||||||
async execute(interaction, args, client) {
|
|
||||||
const content = args.content;
|
|
||||||
const attachment = args.image;
|
|
||||||
|
|
||||||
if (!content && !attachment) {
|
|
||||||
return interaction.reply({ content: 'Uh oh! You are missing any content for me to tweet!', ephemeral: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
await interaction.deferReply({ ephemeral: false });
|
|
||||||
let tweet = content;
|
|
||||||
const date = new Date();
|
|
||||||
|
|
||||||
// If guild is less than 1 month old don't accept the tweet
|
|
||||||
if (interaction.guild.createdAt > date.setMonth(date.getMonth() - 1)) {
|
|
||||||
await interaction.editReply({ content: 'The server need to be 1 month old to be able to use this command!' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the date for the next check
|
|
||||||
date.setTime(Date.now());
|
|
||||||
|
|
||||||
// If the bot has been in the guild for less than 1 week don't accept the tweet.
|
|
||||||
if (interaction.guild.createdAt > date.setDate(date.getDate() - 7)) {
|
|
||||||
await interaction.editReply({ content: 'I need to be in this server for a week to be able to use this command!' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the date for the next check
|
|
||||||
date.setTime(Date.now());
|
|
||||||
|
|
||||||
// If account is less than 6 months old don't accept the tweet ( alt prevention )
|
|
||||||
if (interaction.user.createdAt > date.setMonth(date.getMonth() - 6)) {
|
|
||||||
await interaction.editReply({ content: 'Your account is too new to be able to use this command!' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the date for the next check
|
|
||||||
date.setTime(Date.now());
|
|
||||||
|
|
||||||
// If account is less than 1 year old don't accept attachment
|
|
||||||
if (attachment && interaction.user.createdAt > date.setFullYear(date.getFullYear() - 1)) {
|
|
||||||
await interaction.editReply({ content: 'Your account need to be 1 year or older to be able to send attachment!' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tweet) {
|
|
||||||
// remove zero width space
|
|
||||||
tweet = tweet.replace('', '');
|
|
||||||
// This should only happen if someone tweets a zero width space
|
|
||||||
if (tweet.length === 0) {
|
|
||||||
return interaction.reply({ content: 'Uh oh! You are missing any content for me to tweet!', ephemeral: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
wordToCensor.forEach(async word => {
|
|
||||||
if (tweet.toLowerCase().includes(word.toLowerCase())) {
|
|
||||||
const body = { type:'tweet', uid: interaction.user.id, reason: 'Automatic ban from banned word.' };
|
|
||||||
Blacklists.create(body);
|
|
||||||
|
|
||||||
await interaction.editReply({ content: 'Sike, you just posted cringe! Enjoy the blacklist :)' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Detect banned word (Blacklist the user directly)
|
|
||||||
/* No worky (I don't remember what the fuck I wrote here)
|
|
||||||
if (wordToCensor.includes(tweet) || wordToCensor.includes(tweet.substring(0, tweet.length - 1)) || wordToCensor.includes(tweet.substring(1, tweet.length))) {
|
|
||||||
const body = { type:'tweet', uid: interaction.user.id, reason: 'Automatic ban from banned word.' };
|
|
||||||
Blacklists.create(body);
|
|
||||||
|
|
||||||
await interaction.editReply({ content: 'Sike, you just posted cringe! Enjoy the blacklist :)' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Very simple link detection
|
|
||||||
if (new RegExp('([a-zA-Z0-9]+://)?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+@)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?(/.*)?').test(tweet) && !tweet.includes('twitter.com')) {
|
|
||||||
await interaction.editReply({ content: 'You may not tweet links outside of twitter.com' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Do not allow discord invites
|
|
||||||
if (tweet.includes('discord.gg') || tweet.includes('discord.com/invite/')) {
|
|
||||||
await interaction.editReply({ content: 'No discord invite allowed.' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const userClient = new TwitterApi({
|
|
||||||
appKey: twiConsumer,
|
|
||||||
appSecret: twiConsumerSecret,
|
|
||||||
accessToken: twiToken,
|
|
||||||
accessSecret: twiTokenSecret,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Make sure there is an attachment and if its an image
|
|
||||||
if (attachment) {
|
|
||||||
if (attachment.name.toLowerCase().endsWith('.jpg') || attachment.name.toLowerCase().endsWith('.png') || attachment.name.toLowerCase().endsWith('.gif')) {
|
|
||||||
const streamPipeline = util.promisify(stream.pipeline);
|
|
||||||
const res = await fetch(attachment.url);
|
|
||||||
if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.');
|
|
||||||
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${attachment.name}`));
|
|
||||||
|
|
||||||
const file = fs.statSync(`${os.tmpdir()}/${attachment.name}`);
|
|
||||||
const fileSize = file.size / 1000000.0;
|
|
||||||
|
|
||||||
if ((attachment.name.toLowerCase().endsWith('.jpg') || attachment.name.toLowerCase().endsWith('.png')) && fileSize > 5) {
|
|
||||||
return interaction.editReply({ content: 'Images can\'t be larger than 5 MB!' });
|
|
||||||
}
|
|
||||||
else if (attachment.name.toLowerCase().endsWith('.gif') && fileSize > 15) {
|
|
||||||
return interaction.editReply({ content: 'Gifs can\'t be larger than 15 MB!' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const image = await userClient.v1.uploadMedia(`${os.tmpdir()}/${attachment.name}`);
|
|
||||||
Tweet(image);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await interaction.editReply({ content: 'File type not supported, you can only send jpg/png/gif' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Tweet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
await interaction.editReply({ content: 'Oh no, an error has occurred :(' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function Tweet(img) {
|
|
||||||
let options = null;
|
|
||||||
if (img) {
|
|
||||||
options = { media: { media_ids: new Array(img) } };
|
|
||||||
}
|
|
||||||
const tweeted = await userClient.v2.tweet(tweet, options);
|
|
||||||
|
|
||||||
const tweetid = tweeted.data.id;
|
|
||||||
const FunnyWords = ['oppaGangnamStyle', '69', '420', 'cum', 'funnyMan', 'GUCCISmartToilet', 'TwitterForClowns', 'fart', 'ok', 'hi', 'howAreYou', 'WhatsNinePlusTen', '21'];
|
|
||||||
const TweetLink = `https://vxtwitter.com/${FunnyWords[Math.floor((Math.random() * FunnyWords.length))]}/status/${tweetid}`;
|
|
||||||
|
|
||||||
let channel = await client.channels.resolve(twiChannel);
|
|
||||||
channel.send(TweetLink);
|
|
||||||
|
|
||||||
const Embed = new EmbedBuilder()
|
|
||||||
.setAuthor({ name: interaction.user.username, iconURL: interaction.user.displayAvatarURL() })
|
|
||||||
.setDescription(tweet ? tweet : 'No content.')
|
|
||||||
.addFields(
|
|
||||||
{ name: 'Link', value: TweetLink, inline: true },
|
|
||||||
{ name: 'Tweet ID', value: tweetid, inline: true },
|
|
||||||
{ name: 'Channel ID', value: interaction.channel.id, inline: true },
|
|
||||||
{ name: 'Message ID', value: interaction.id, inline: true },
|
|
||||||
{ name: 'Author', value: `${interaction.user.username} (${interaction.user.id})`, inline: true },
|
|
||||||
)
|
|
||||||
.setTimestamp();
|
|
||||||
|
|
||||||
if (interaction.guild) {
|
|
||||||
Embed.addFields(
|
|
||||||
{ name: 'Guild', value: `${interaction.guild.name} (${interaction.guild.id})`, inline: true },
|
|
||||||
{ name: 'message link', value: `https://discord.com/channels/${interaction.guild.id}/${interaction.channel.id}/${interaction.id}`, inline: true },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Embed.addFields({ name: 'message link', value: `https://discord.com/channels/@me/${interaction.channel.id}/${interaction.id}` });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attachment) Embed.setImage(attachment.url);
|
|
||||||
|
|
||||||
channel = await client.channels.resolve(twiLogChannel);
|
|
||||||
channel.send({ embeds: [Embed] });
|
|
||||||
return interaction.editReply({ content: `Go see ur epic tweet ${TweetLink}` });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
99
commands/fun/vidshittyfier.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const os = require('os');
|
||||||
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
|
const attachment = require('../../utils/attachment');
|
||||||
|
const downloader = require('../../utils/download');
|
||||||
|
|
||||||
|
class vidshittyfierCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('vidshittyfier', {
|
||||||
|
aliases: ['vidshittyfier', 'vs', 'shittyfier', 'vid2shit', 'v2s'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'url',
|
||||||
|
unordered: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'compression',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
unordered: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Compress your videos and lower their quality!',
|
||||||
|
usage: '[link to video] [lighter compression (True or false)]',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let vid;
|
||||||
|
if (args.link)
|
||||||
|
vid = args.link.href;
|
||||||
|
else
|
||||||
|
vid = await attachment(message);
|
||||||
|
|
||||||
|
let output = `${os.tmpdir()}/tmp${message.id}.mp4`;
|
||||||
|
let output2 = `${os.tmpdir()}/Shittyfied${message.id}.mp4`;
|
||||||
|
|
||||||
|
let compression = '30k';
|
||||||
|
let audioCompression = '60k';
|
||||||
|
|
||||||
|
if (args.compression) {
|
||||||
|
compression = '50k';
|
||||||
|
audioCompression = '100k';
|
||||||
|
}
|
||||||
|
|
||||||
|
let loadingmsg = await message.channel.send('Processing <a:loadingmin:527579785212329984>');
|
||||||
|
|
||||||
|
downloader(vid, null, `${os.tmpdir()}/${message.id}.mp4`)
|
||||||
|
.on('error', async err => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send(err, { code: true });
|
||||||
|
})
|
||||||
|
.on('end', async downloadOutput => {
|
||||||
|
let ffmpegCommand = ffmpeg(downloadOutput);
|
||||||
|
|
||||||
|
ffmpegCommand.videoFilters('scale=iw/4:ih/4');
|
||||||
|
ffmpegCommand.output(output);
|
||||||
|
ffmpegCommand.run();
|
||||||
|
ffmpegCommand.on('error', (err, stdout, stderr) => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Uh oh, an error has occurred!' + err);
|
||||||
|
});
|
||||||
|
ffmpegCommand.on('end', () => {
|
||||||
|
let ffmpegCommand = ffmpeg(downloadOutput);
|
||||||
|
|
||||||
|
ffmpegCommand.videoFilters('scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2');
|
||||||
|
ffmpegCommand.videoCodec('libx264');
|
||||||
|
ffmpegCommand.fps(15);
|
||||||
|
ffmpegCommand.videoBitrate(compression);
|
||||||
|
ffmpegCommand.audioBitrate(audioCompression);
|
||||||
|
ffmpegCommand.output(output2);
|
||||||
|
ffmpegCommand.run();
|
||||||
|
ffmpegCommand.on('error', (err, stdout, stderr) => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
console.error(`${err}\n${stdout}\n${stderr}`);
|
||||||
|
return message.channel.send('Uh oh, an error has occurred!' + err);
|
||||||
|
});
|
||||||
|
ffmpegCommand.on('end', () => {
|
||||||
|
loadingmsg.delete();
|
||||||
|
message.delete();
|
||||||
|
return message.channel.send(`Shittyfied by ${message.author}`, {files: [output2]})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
return message.channel.send(`${err.name}: ${err.message} ${err.message === 'Request entity too large' ? 'The file size is too big' : ''}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = vidshittyfierCommand;
|
|
@ -1,37 +1,306 @@
|
||||||
import { SlashCommandBuilder } from 'discord.js';
|
const { Command } = require('discord-akairo');
|
||||||
import fs from 'node:fs';
|
const { proxy } = require('../../config.json');
|
||||||
import os from 'node:os';
|
const YTPGenerator = require('ytpplus-node');
|
||||||
import YTPGenerator from 'ytpplus-node';
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const attachment = require('../../utils/attachment');
|
||||||
|
const downloader = require('../../utils/download');
|
||||||
|
const md5File = require('md5-file');
|
||||||
|
const ytpHash = require('../../models').ytpHash;
|
||||||
|
const { ytpChannel } = require('../../config.json');
|
||||||
|
//const ytpblacklist = require('../../models').ytpblacklist;
|
||||||
|
|
||||||
export default {
|
const MAX_CLIPS = 20;
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('ytp')
|
|
||||||
.setDescription('Generate a YTP')
|
class ytpCommand extends Command {
|
||||||
.addBooleanOption(option =>
|
constructor() {
|
||||||
option.setName('force')
|
super('ytp', {
|
||||||
.setDescription('Force the generation of the video in non-nsfw channel.')
|
aliases: ['ytp', 'ytpplus', 'ytp+'],
|
||||||
.setRequired(false)),
|
|
||||||
category: 'fun',
|
category: 'fun',
|
||||||
ratelimit: 2,
|
clientPermissions: ['ATTACH_FILES', 'SEND_MESSAGES'],
|
||||||
cooldown: 60,
|
args: [
|
||||||
parallelLimit: 30,
|
{
|
||||||
async execute(interaction, args) {
|
id: 'add',
|
||||||
if (!interaction.channel.nsfw && !args.force) return interaction.reply(`Please execute this command in an NSFW channel ( Content might not be NSFW but since the video are user submitted better safe than sorry ) OR do \`\`${interaction.prefix}ytp --force\`\` to make the command work outside of nsfw channel BE AWARE THAT IT WON'T CHANGE THE FINAL RESULT SO NSFW CAN STILL HAPPEN`);
|
match: 'flag',
|
||||||
|
flag: ['--add']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'pool',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--pool']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'force',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--force']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'randomSound',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--randomSound']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'randomSoundMute',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--randomSoundMute']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reverse',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--reverse']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'chorus',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--chorus']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vibrato',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--vibrato']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'highPitch',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--highPitch']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lowPitch',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--lowPitch']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'speedUp',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--speedUp']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'slowDown',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--slowDown']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dance',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--dance']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'squidward',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--squidward']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'how',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--how']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'debug',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--debug']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'url',
|
||||||
|
prompt: {
|
||||||
|
start: 'Please send the URL of which video you want to download. Say `cancel` to stop the command',
|
||||||
|
retry: 'Please send a valid URL of the video you want to download. Say `cancel` to stop the command',
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
unordered: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'max',
|
||||||
|
type: 'string',
|
||||||
|
unordered: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'proxy',
|
||||||
|
match: 'option',
|
||||||
|
flag: ['--proxy'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'listproxy',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--listproxy', '--proxylist']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Generate random ytp\n--add with a link or attachment to add a video to the pool, only .mp4 work **(Everything submitted here is logged and can get you blacklisted if you post lots of repeated content, post porn/gore, post TOS breaking content)**\n--pool to see how many vid there is currently in the pool\n--force to make the command work outside of nsfw channel BE AWARE THAT IT WON\'T CHANGE THE FINAL RESULT SO NSFW CAN STILL HAPPEN\n`--proxy #` to select a proxy, `--listproxy` to see a list of proxy',
|
||||||
|
usage: '(OPTIONAL) | [Minimum length of clip] [Max length of clip]',
|
||||||
|
examples: ['5 10', '--add https://www.youtube.com/watch?v=6n3pFFPSlW4', '--add https://www.youtube.com/watch?v=6n3pFFPSlW4 --proxy 1', '--listproxy']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (args.pool) {
|
||||||
|
let mp4 = [];
|
||||||
|
fs.readdirSync('./asset/ytp/userVid/').forEach(file => {
|
||||||
|
if (file.endsWith('mp4')) {
|
||||||
|
mp4.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return message.reply(`There is currently ${mp4.length} videos, you can add yours by doing \`\`${this.client.commandHandler.prefix[0]}ytp --add (link or attachment)\`\``);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.listproxy) {
|
||||||
|
let proxys = [];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
proxy.forEach(proxy => {
|
||||||
|
i++;
|
||||||
|
proxys.push(`[${i}] ${ proxy.hideip ? '[IP HIDDEN]' : proxy.ip.substring(0, proxy.ip.length - 5)} - ${proxy.country}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const Embed = this.client.util.embed()
|
||||||
|
.setColor(message.member ? message.member.displayHexColor : 'NAVY')
|
||||||
|
.setTitle('List of available proxy')
|
||||||
|
.setDescription(proxys.join('\n'))
|
||||||
|
.setFooter('You can help me get more proxy by either donating to me or providing a proxy for me');
|
||||||
|
|
||||||
|
return message.reply(Embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.add) {
|
||||||
|
/*
|
||||||
|
const blacklist = await ytpblacklist.findOne({where: {userID:message.author.id}});
|
||||||
|
|
||||||
|
if (blacklist) {
|
||||||
|
return message.reply(`You have been blacklisted for the following reasons: \`${blacklist.get('reason')}\` be less naughty next time.`);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (args.proxy && !args.proxyAuto) { // args.proxyAuto is only provided when the command is run after a error 429
|
||||||
|
args.proxy = args.proxy -1;
|
||||||
|
if (!proxy[args.proxy]) args.proxy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let loadingmsg = await message.reply('Downloading <a:loadingmin:527579785212329984>');
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (args.link)
|
||||||
|
url = args.link.href;
|
||||||
|
else
|
||||||
|
url = await attachment(message);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
let options = ['--format=mp4'];
|
||||||
|
|
||||||
|
if (args.proxy) {
|
||||||
|
options.push('--proxy');
|
||||||
|
options.push(proxy[args.proxy].ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return downloader(url, options, `./asset/ytp/userVid/${message.id}.mp4`)
|
||||||
|
.on('error', (err) => {
|
||||||
|
if (err.includes('HTTP Error 429: Too Many Requests')) {
|
||||||
|
if (args.proxy != null) {
|
||||||
|
args.proxy = args.proxy + 1;
|
||||||
|
} else {
|
||||||
|
args.proxy = 0;
|
||||||
|
args.proxyAuto = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!proxy[args.proxy]) return message.reply('`HTTP Error 429: Too Many Requests.`\nThe website you tried to download from probably has the bot blocked along with its proxy');
|
||||||
|
|
||||||
|
loadingmsg.delete();
|
||||||
|
return this.client.commandHandler.runCommand(message, this.client.commandHandler.findCommand('ytp'), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.includes('Error: status code 403')) return message.reply('`HTTP Error 403: Forbidden.`\nThe video you tried to download is not publicly available therefor the bot can\'t download it.');
|
||||||
|
|
||||||
|
return message.reply(err, { code: true });
|
||||||
|
|
||||||
|
})
|
||||||
|
.on('end', async output => {
|
||||||
|
const hash = md5File.sync(output);
|
||||||
|
const ytphash = await ytpHash.findOne({where: {hash: hash}});
|
||||||
|
|
||||||
|
if (ytphash) {
|
||||||
|
fs.unlinkSync(output);
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.reply('This video is a duplicate... Not adding.');
|
||||||
|
} else {
|
||||||
|
let file = fs.statSync(output);
|
||||||
|
let fileSize = file.size / 1000000.0;
|
||||||
|
|
||||||
|
if (fileSize > 50) {
|
||||||
|
fs.unlinkSync(output);
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.reply('Video too big.. Not adding.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = {hash: hash, messageID: message.id};
|
||||||
|
await ytpHash.create(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let mp4 = [];
|
||||||
|
fs.readdirSync('./asset/ytp/userVid/').forEach(file => {
|
||||||
|
if (file.endsWith('mp4')) {
|
||||||
|
mp4.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// (Hopefully) limit video to 2k
|
||||||
|
if (mp4.length > 2000) {
|
||||||
|
let file = mp4.sort((a, b) => {
|
||||||
|
let time1 = fs.statSync(`./asset/ytp/userVid/${b}`).ctime;
|
||||||
|
let time2 = fs.statSync(`./asset/ytp/userVid/${a}`).ctime;
|
||||||
|
if (time1 < time2) return 1;
|
||||||
|
if (time1 > time2) return -1;
|
||||||
|
return 0;
|
||||||
|
}).slice(0,1);
|
||||||
|
console.log(file);
|
||||||
|
fs.unlinkSync(`./asset/ytp/userVid/${file[0]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingmsg.delete();
|
||||||
|
message.reply(`Video successfully added to the pool! There is now ${mp4.length} videos`);
|
||||||
|
|
||||||
|
const Embed = this.client.util.embed()
|
||||||
|
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
||||||
|
.addField('Channel ID', message.channel.id, true)
|
||||||
|
.addField('Messsage ID', message.id, true)
|
||||||
|
.addField('Author', `${message.author.username} (${message.author.id})`, true)
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (message.guild) {
|
||||||
|
Embed.addField('Guild', `${message.guild.name} (${message.guild.id})`, true);
|
||||||
|
Embed.addField('Message link', `https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.id}`);
|
||||||
|
} else {
|
||||||
|
Embed.addField('Message link', `https://discord.com/channels/@me/${message.channel.id}/${message.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let channel = this.client.channels.resolve(ytpChannel);
|
||||||
|
return channel.send(url, {embed: Embed});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.reply('You need a valid video link!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!message.channel.nsfw && !args.force) return message.reply(`Please execute this command in an NSFW channel ( Content might not be NSFW but since the video are user submitted better safe than sorry ) OR do \`\`${this.client.commandHandler.prefix[0]}ytp --force\`\` to make the command work outside of nsfw channel BE AWARE THAT IT WON'T CHANGE THE FINAL RESULT SO NSFW CAN STILL HAPPEN`);
|
||||||
|
|
||||||
// Read userVid folder and select random vid and only take .mp4
|
// Read userVid folder and select random vid and only take .mp4
|
||||||
const mp4 = [];
|
let mp4 = [];
|
||||||
const asset = [];
|
let asset = [];
|
||||||
// Count number of total vid
|
// Count number of total vid
|
||||||
fs.readdirSync('./asset/ytp/userVid/').forEach(file => {
|
fs.readdirSync('./asset/ytp/userVid/').forEach(file => {
|
||||||
if (file.endsWith('mp4')) {
|
if (file.endsWith('mp4')) {
|
||||||
mp4.push(file);
|
mp4.push(file);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const MAX_CLIPS = 20;
|
|
||||||
// Select random vid depending on the amount of MAX_CLIPS
|
// Select random vid depending on the amount of MAX_CLIPS
|
||||||
for (let i = 0; i < MAX_CLIPS; i++) {
|
for (let i = 0; i < MAX_CLIPS; i++) {
|
||||||
const random = Math.floor(Math.random() * mp4.length);
|
let random = Math.floor(Math.random() * mp4.length);
|
||||||
const vid = `./asset/ytp/userVid/${mp4[random]}`;
|
let vid = `./asset/ytp/userVid/${mp4[random]}`;
|
||||||
if (mp4[random].endsWith('mp4')) {
|
if (mp4[random].endsWith('mp4')) {
|
||||||
if (!asset.includes(vid)) {
|
if (!asset.includes(vid)) {
|
||||||
asset.push(vid);
|
asset.push(vid);
|
||||||
|
@ -39,11 +308,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadingmsg = await interaction.reply(`Processing, this can take a ***long*** time, i'll ping you when I finished <a:loadingmin:527579785212329984>\nSome info: There are currently ${mp4.length} videos, why not add yours? You can do so with the \`\`addytp\`\` command.\nLike ytp? Why not check out https://ytp.namejeff.xyz/`);
|
let loadingmsg = await message.reply(`Processing, this can take a ***long*** time, i'll ping you when i finished <a:loadingmin:527579785212329984>\nSome info: There are currently ${mp4.length} videos, you can add yours by doing \`\`${this.client.commandHandler.prefix[0]}ytp --add (link or attachment)\`\`\nLike ytp? Why not check out https://ytp.namejeff.xyz/`);
|
||||||
|
|
||||||
const options = {
|
|
||||||
debug: false,
|
let options = {
|
||||||
MAX_STREAM_DURATION: Math.floor((Math.random() * 3) + 1),
|
debug: args.debug,
|
||||||
|
MIN_STREAM_DURATION: args.link ? Math.floor(args.link) : null,
|
||||||
|
MAX_STREAM_DURATION: args.link && args.max ? args.max : Math.floor((Math.random() * 3) + 1), // Random duration of video clip
|
||||||
sources: './asset/ytp/sources/',
|
sources: './asset/ytp/sources/',
|
||||||
sounds: './asset/ytp/sounds/',
|
sounds: './asset/ytp/sounds/',
|
||||||
music: './asset/ytp/music/',
|
music: './asset/ytp/music/',
|
||||||
|
@ -52,39 +323,58 @@ export default {
|
||||||
sourceList: asset,
|
sourceList: asset,
|
||||||
intro: args.force ? './asset/ytp/intro.mp4' : null,
|
intro: args.force ? './asset/ytp/intro.mp4' : null,
|
||||||
outro: './asset/ytp/outro.mp4',
|
outro: './asset/ytp/outro.mp4',
|
||||||
OUTPUT_FILE: `${os.tmpdir()}/${interaction.id}_YTP.mp4`,
|
OUTPUT_FILE: `${os.tmpdir()}/${message.id}_YTP.mp4`,
|
||||||
MAX_CLIPS: MAX_CLIPS,
|
MAX_CLIPS: MAX_CLIPS,
|
||||||
transitions: true,
|
transitions: true,
|
||||||
showFileNames: true,
|
showFileNames: true,
|
||||||
effects: {
|
effects: {
|
||||||
effect_RandomSound: true,
|
effect_RandomSound: !args.randomSound,
|
||||||
effect_RandomSoundMute: true,
|
effect_RandomSoundMute: !args.randomSoundMute,
|
||||||
effect_Reverse: true,
|
effect_Reverse: !args.reverse,
|
||||||
effect_Chorus: true,
|
effect_Chorus: !args.chorus,
|
||||||
effect_Vibrato: true,
|
effect_Vibrato: !args.vibrato,
|
||||||
effect_HighPitch: true,
|
effect_HighPitch: !args.highPitch,
|
||||||
effect_LowPitch: true,
|
effect_LowPitch: !args.lowPitch,
|
||||||
effect_SpeedUp: true,
|
effect_SpeedUp: !args.speedUp,
|
||||||
effect_SlowDown: true,
|
effect_SlowDown: !args.slowDown,
|
||||||
effect_Dance: true,
|
effect_Dance: !args.dance,
|
||||||
effect_Squidward: true,
|
effect_Squidward: !args.squidward,
|
||||||
effect_How: true,
|
effect_How: !args.how
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await new YTPGenerator().configurateAndGo(options)
|
new YTPGenerator().configurateAndGo(options)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
md5File(`${os.tmpdir()}/${message.id}_YTP.mp4`).then(async hash => {
|
||||||
|
const body = {hash: hash, messageID: message.id};
|
||||||
|
await ytpHash.create(body);
|
||||||
|
});
|
||||||
loadingmsg.delete();
|
loadingmsg.delete();
|
||||||
return interaction.followUp({ content: 'Here is your YTP! Remember, it might contain nsfw, so be careful!', files: [`${os.tmpdir()}/${interaction.id}_YTP.mp4`] })
|
return message.reply('Here is your YTP! Remember, it might contain nsfw, so be careful!', {files: [`${os.tmpdir()}/${message.id}_YTP.mp4`]})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return interaction.followUp({ files: [`./asset/ytp/error${Math.floor(Math.random() * 2) + 1}.mp4`] });
|
return message.reply('Whoops, look like the vid might be too big for discord, my bad, please try again');
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
loadingmsg.delete();
|
loadingmsg.delete();
|
||||||
return interaction.followUp({ files: [`./asset/ytp/error${Math.floor(Math.random() * 2) + 1}.mp4`] });
|
if (!args.retry)
|
||||||
|
args.retry = 0;
|
||||||
|
else
|
||||||
|
args.retry += 1;
|
||||||
|
|
||||||
|
if (args.retry === 3) {
|
||||||
|
return message.reply({files: [Math.random() < 0.5 ? './asset/ytp/error1.mp4' : './asset/ytp/error2.mp4']})
|
||||||
|
.catch(err => { // In case it can't send the video for some reason
|
||||||
|
console.error(err);
|
||||||
|
return message.reply('Oh no, an error has occurred! please try again. If this happens alot, you should report this to the developers.');
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
|
||||||
|
return this.client.commandHandler.runCommand(message, this.client.commandHandler.findCommand('ytp'), args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ytpCommand;
|
||||||
|
|
265
commands/fun/ytp.js.dev
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const YTPGenerator = require('ytpplus-node');
|
||||||
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const youtubedl = require('youtube-dl');
|
||||||
|
let queue = 0;
|
||||||
|
|
||||||
|
class ytpCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('ytp', {
|
||||||
|
aliases: ['ytp', 'ytpplus', 'ytp+'],
|
||||||
|
category: 'fun',
|
||||||
|
clientPermissions: ['ATTACH_FILES', 'SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'add',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--add']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'pool',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--pool']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'force',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--force']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'randomSound',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--randomSound']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'randomSoundMute',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--randomSoundMute']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reverse',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--reverse']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'chorus',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--chorus']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vibrato',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--vibrato']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'highPitch',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--highPitch']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lowPitch',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--lowPitch']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'speedUp',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--speedUp']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'slowDown',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--slowDown']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dance',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--dance']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'squidward',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--squidward']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'debug',
|
||||||
|
match: 'flag',
|
||||||
|
flag: ['--debug']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'link',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Generate random ytp | --add with a link or attachment to add a video to the pool, only .mp4 work | --pool to see how many vid there is currently in the pool | --force to make the command work outside of nsfw channel BE AWARE THAT IT WON\'T CHANGE THE FINAL RESULT SO NSFW CAN STILL HAPPEN',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
console.log(queue);
|
||||||
|
let prefix = this.client.commandHandler.prefix[0];
|
||||||
|
let MAX_CLIPS = 20;
|
||||||
|
|
||||||
|
if (args.pool) {
|
||||||
|
let mp4 = [];
|
||||||
|
fs.readdirSync('./asset/ytp/userVid/').forEach(file => {
|
||||||
|
if (file.endsWith('mp4')) {
|
||||||
|
mp4.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return message.channel.send(`There is currently ${mp4.length} videos, you can add yours by doing \`\`${prefix}ytp --add (link or attachment)\`\``);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.add) {
|
||||||
|
let loadingmsg = await message.channel.send('Downloading <a:loadingmin:527579785212329984>');
|
||||||
|
let Attachment = (message.attachments).array();
|
||||||
|
let url = args.link;
|
||||||
|
// Get attachment link
|
||||||
|
if (Attachment[0] && !args.link) {
|
||||||
|
url = Attachment[0].url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
return youtubedl.exec(url, ['--no-playlist','--max-filesize', '50m', '--format=mp4', '-o', `./asset/ytp/userVid/${message.id}.mp4`], {}, function(err, output) {
|
||||||
|
console.log(output);
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send('An error has occured, I can\'t download from the link you provided. Is it an mp4?');
|
||||||
|
} else {
|
||||||
|
if (output[2]) {
|
||||||
|
if (output[2].includes('File is larger than max-filesize')) {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send(output[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mp4 = [];
|
||||||
|
fs.readdirSync('./asset/ytp/userVid/').forEach(file => {
|
||||||
|
if (file.endsWith('mp4')) {
|
||||||
|
mp4.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.reply(`Video sucessfully added to the pool! There is now ${mp4.length} videos`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.channel.send('You need a valid video link!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!message.channel.nsfw && !args.force) return message.channel.send(`Please execute this command in an NSFW channel ( Content might not be NSFW but since the video are user submitted better safe than sorry ) OR do \`\`${prefix}ytp --force\`\` to make the command work outside of nsfw channel BE AWARE THAT IT WON'T CHANGE THE FINAL RESULT SO NSFW CAN STILL HAPPEN`);
|
||||||
|
|
||||||
|
if (queue >= 1) {
|
||||||
|
let curQueue = queue;
|
||||||
|
message.channel.send(`The execution of this command has been placed in a queue, you are #${curQueue}/${queue} in the queue`);
|
||||||
|
|
||||||
|
let reminder = setInterval(() => {
|
||||||
|
message.channel.send(`The execution of this command has been placed in a queue, you are #${curQueue}/${queue} in the queue`);
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
let checkQueue = setInterval(() => {
|
||||||
|
console.log(queue);
|
||||||
|
console.log(curQueue);
|
||||||
|
if (curQueue < 1) {
|
||||||
|
clearInterval(checkQueue);
|
||||||
|
clearInterval(reminder);
|
||||||
|
makeYTP();
|
||||||
|
}
|
||||||
|
if (queue < curQueue) curQueue = queue;
|
||||||
|
}, 1000);
|
||||||
|
//queue++;
|
||||||
|
} else {
|
||||||
|
//queue++;
|
||||||
|
makeYTP();
|
||||||
|
}
|
||||||
|
|
||||||
|
queue++;
|
||||||
|
|
||||||
|
async function makeYTP() {
|
||||||
|
console.log('making ytp');
|
||||||
|
// Read userVid folder and select random vid and only take .mp4
|
||||||
|
let mp4 = [];
|
||||||
|
let asset = [];
|
||||||
|
let files = fs.readdirSync('./asset/ytp/userVid/');
|
||||||
|
// Count number of total vid
|
||||||
|
files.forEach(file => {
|
||||||
|
if (file.endsWith('mp4')) {
|
||||||
|
mp4.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Select random vid depending on the amount of MAX_CLIPS
|
||||||
|
for (let i = 0; i < MAX_CLIPS; i++) {
|
||||||
|
let random = Math.floor(Math.random() * files.length);
|
||||||
|
let vid = `./asset/ytp/userVid/${files[random]}`;
|
||||||
|
if (files[random].endsWith('mp4')) {
|
||||||
|
if (!asset.includes(vid)) {
|
||||||
|
asset.push(vid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let loadingmsg = await message.channel.send(`Processing, this can take a **long** time, i'll ping you when i finished <a:loadingmin:527579785212329984>\nSome info: There is currently ${mp4.length} videos, you can add yours by doing \`\`${prefix}ytp --add (link or attachment)\`\``);
|
||||||
|
|
||||||
|
|
||||||
|
let options = {
|
||||||
|
debug: args.debug,
|
||||||
|
MAX_STREAM_DURATION: args.link ? args.link : Math.floor((Math.random() * 3) + 1), // Random duration of video clip
|
||||||
|
sources: './asset/ytp/sources/',
|
||||||
|
sounds: './asset/ytp/sounds/',
|
||||||
|
music: './asset/ytp/music/',
|
||||||
|
resources: './asset/ytp/resources/',
|
||||||
|
temp: os.tmpdir(),
|
||||||
|
sourceList: asset,
|
||||||
|
outro: './asset/ytp/outro.mp4', // Need an outro or it won't work
|
||||||
|
OUTPUT_FILE: `${os.tmpdir()}/${message.id}_YTP.mp4`,
|
||||||
|
MAX_CLIPS: MAX_CLIPS,
|
||||||
|
transitions: true,
|
||||||
|
effects: {
|
||||||
|
effect_RandomSound: args.randomSound,
|
||||||
|
effect_RandomSoundMute: args.randomSoundMute,
|
||||||
|
effect_Reverse: args.reverse,
|
||||||
|
effect_Chorus: args.chorus,
|
||||||
|
effect_Vibrato: args.vibrato,
|
||||||
|
effect_HighPitch: args.highPitch,
|
||||||
|
effect_LowPitch: args.lowPitch,
|
||||||
|
effect_SpeedUp: args.speedUp,
|
||||||
|
effect_SlowDown: args.slowDown,
|
||||||
|
effect_Dance: args.dance,
|
||||||
|
effect_Squidward: args.squidward
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new YTPGenerator().configurateAndGo(options)
|
||||||
|
.then(() => {
|
||||||
|
queue--;
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.reply('Here is your YTP!', {files: [`${os.tmpdir()}/${message.id}_YTP.mp4`]})
|
||||||
|
.catch(() => {
|
||||||
|
return message.channel.send('Whoops, look like the vid might be too big for discord, my bad, please try again');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
queue--;
|
||||||
|
console.error(err);
|
||||||
|
loadingmsg.delete();
|
||||||
|
return message.reply('Oh no! An error has occured!');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ytpCommand;
|
33
commands/general/advice.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
class AdviceCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('advice', {
|
||||||
|
aliases: ['advice'],
|
||||||
|
category: 'general',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'EMBED_LINKS'],
|
||||||
|
description: {
|
||||||
|
content: 'Send some random advices',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message) {
|
||||||
|
fetch('http://api.adviceslip.com/advice').then((response) => {
|
||||||
|
return response.json();
|
||||||
|
}).then((response) => {
|
||||||
|
const adviceEmbed = this.client.util.embed()
|
||||||
|
.setColor(message.member ? message.member.displayHexColor : 'NAVY')
|
||||||
|
.setTitle(response.slip.id)
|
||||||
|
.setDescription(response.slip.advice);
|
||||||
|
|
||||||
|
|
||||||
|
message.reply(adviceEmbed);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = AdviceCommand;
|
37
commands/general/clap.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const rand = require('../../rand.js');
|
||||||
|
class ClapCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('clap', {
|
||||||
|
aliases: ['clap'],
|
||||||
|
category: 'general',
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can replace the space with 👏',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'replace 👏 the 👏 spaces 👏 with 👏 clap 👏',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['replace the spaces with clap']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
if (!args.text)
|
||||||
|
return;
|
||||||
|
args.text = rand.random(args.text, message);
|
||||||
|
|
||||||
|
let clap = args.text.replace(/ /g, ' 👏 ');
|
||||||
|
message.reply(`${clap} 👏`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ClapCommand;
|
44
commands/general/emotesay.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const emojiCharacters = require('../../emojiCharacters');
|
||||||
|
const rand = require('../../rand.js');
|
||||||
|
|
||||||
|
class EmotesayCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('emotesay', {
|
||||||
|
aliases: ['emotesay', 'esay'],
|
||||||
|
category: 'general',
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can replace the space with dancing emote',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Replace the text you send with dancing letters',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['Hello']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let text = args.text;
|
||||||
|
if (!text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text = rand.random(text, message);
|
||||||
|
|
||||||
|
message.delete();
|
||||||
|
let emojiArray = [];
|
||||||
|
for (let i = 0; i < text.length; i++)
|
||||||
|
emojiArray[i] = emojiCharacters[text.toLowerCase().split('')[i]];
|
||||||
|
message.channel.send(emojiArray.join(''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = EmotesayCommand;
|
66
commands/general/facebook
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const Filter = require('bad-words');
|
||||||
|
let filter = new Filter();
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const reload = require('auto-reload');
|
||||||
|
const rand = require('../../rand.js');
|
||||||
|
const { fbChannel, fbToken } = require('../../config.json');
|
||||||
|
|
||||||
|
class facebookCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('facebook', {
|
||||||
|
aliases: ['facebook', 'fb'],
|
||||||
|
category: 'general',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Post your message to the bot facebook page',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['epic']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let text = args.text;
|
||||||
|
|
||||||
|
let censor = reload('../../json/censor.json');
|
||||||
|
let uncensor = reload('../../json/uncensor.json');
|
||||||
|
filter.addWords(...censor);
|
||||||
|
filter.removeWords(...uncensor);
|
||||||
|
|
||||||
|
const blacklist = reload('../../json/Blacklist.json');
|
||||||
|
const channel = this.client.channels.get(fbChannel);
|
||||||
|
|
||||||
|
if (blacklist.includes(message.author.id)) {
|
||||||
|
return message.channel.send('You have been blacklisted from this command... be less naughty next time.');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Filter out swear word
|
||||||
|
text = filter.clean(text);
|
||||||
|
|
||||||
|
text = rand.random(text, message);
|
||||||
|
text = encodeURI(text);
|
||||||
|
|
||||||
|
fetch(`https://graph.facebook.com/v3.2/1254967721332652/feed?message=${text}&access_token=${fbToken}`, {
|
||||||
|
method: 'post',
|
||||||
|
}).then((response) => {
|
||||||
|
return response.json();
|
||||||
|
}).then((response) => {
|
||||||
|
console.log(response);
|
||||||
|
let postID;
|
||||||
|
if (response.id) {
|
||||||
|
postID = response.id.slice(17);
|
||||||
|
}
|
||||||
|
message.channel.send(`Go see ur epic post https://www.facebook.com/HahaYesDiscord/posts/${postID}`);
|
||||||
|
channel.send(`AUTHOR: ${message.author.username} (${message.author.id}) Sent: ${args.text}\nhttps://www.facebook.com/HahaYesDiscord/posts/${postID}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = facebookCommand;
|
49
commands/general/memerclub.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const { memerToken } = require('../../config.json');
|
||||||
|
|
||||||
|
class memerclubCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('memerclub', {
|
||||||
|
aliases: ['memerclub'],
|
||||||
|
category: 'general',
|
||||||
|
clientPermissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Post whatever you like on https://memerclub.gamingti.me ! ( no rules, go wild )',
|
||||||
|
usage: '',
|
||||||
|
examples: ['']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let Attachment = (message.attachments).array();
|
||||||
|
let img = '';
|
||||||
|
if (!Attachment[0] && !args.text) return message.channel.send('You need to input something for me to post!');
|
||||||
|
if (Attachment[0]) {
|
||||||
|
img = Attachment[0].url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.text)
|
||||||
|
if (args.text.includes('discord.gg')) return message.channel.send('No discord invite allowed.');
|
||||||
|
|
||||||
|
fetch(`https://memerclub.gamingti.me/api/post/?token=${memerToken}&text=${encodeURI(args.text)}&image=${img}`)
|
||||||
|
.then((response) => {
|
||||||
|
return response.json();
|
||||||
|
}).then((response) => {
|
||||||
|
console.log(response);
|
||||||
|
if (response.error) return message.channel.send(response.error);
|
||||||
|
message.channel.send(`Go check your epic post!\nhttps://memerclub.gamingti.me/post/${response.uuid}`)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = memerclubCommand;
|
34
commands/general/randomizer.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
|
||||||
|
class randomizerCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('randomizer', {
|
||||||
|
aliases: ['randomizer'],
|
||||||
|
category: 'general',
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Need words to randomize',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Choose one random word',
|
||||||
|
usage: '[multiples words]',
|
||||||
|
examples: ['Hello bye']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let words = args.text.split(' ');
|
||||||
|
|
||||||
|
return message.reply(words[Math.floor((Math.random() * words.length))]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = randomizerCommand;
|
168
commands/general/say.js
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
const { Command } = require('discord-akairo');
|
||||||
|
const { MessageEmbed } = require('discord.js');
|
||||||
|
const rand = require('../../rand.js');
|
||||||
|
|
||||||
|
class SayCommand extends Command {
|
||||||
|
constructor() {
|
||||||
|
super('say', {
|
||||||
|
aliases: ['say', 'sayd'],
|
||||||
|
category: 'general',
|
||||||
|
clientPermissions: ['SEND_MESSAGES'],
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
id: 'text',
|
||||||
|
type: 'string',
|
||||||
|
prompt: {
|
||||||
|
start: 'Write something so i can say it back',
|
||||||
|
},
|
||||||
|
match: 'rest'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
description: {
|
||||||
|
content: 'Repeat what you say, (Use sayd to delete your message) [Click here to see the complete list of "tag"](https://cdn.discordapp.com/attachments/502198809355354133/561043193949585418/unknown.png)',
|
||||||
|
usage: '[text]',
|
||||||
|
examples: ['[member] is a big [adverbs] [verbs]']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(message, args) {
|
||||||
|
let text = args.text;
|
||||||
|
if (!text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text = rand.random(text, message);
|
||||||
|
|
||||||
|
let attach = '';
|
||||||
|
|
||||||
|
if (text.includes('[attach:')) {
|
||||||
|
attach = text.split(/(\[attach:.*?])/);
|
||||||
|
for (let i = 0, l = attach.length; i < l; i++) {
|
||||||
|
if (attach[i].includes('[attach:')) {
|
||||||
|
attach = attach[i].replace('[attach:', '').slice(0, -1);
|
||||||
|
i = attach.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text = text.replace(/(\[attach:.*?])/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// THIS SECTION IS VERY VERY BAD MUST CHANGE
|
||||||
|
if (text.includes('[embed]')) {
|
||||||
|
text = text.replace(/\[embed\]/, ' ');
|
||||||
|
|
||||||
|
let title = '';
|
||||||
|
let desc = '';
|
||||||
|
let image;
|
||||||
|
let thumbnail;
|
||||||
|
let footer = '';
|
||||||
|
let color;
|
||||||
|
|
||||||
|
if (text.includes('[embedImage:')) {
|
||||||
|
image = text.split(/(\[embedImage:.*?])/);
|
||||||
|
|
||||||
|
for (let i = 0, l = image.length; i < l; i++) {
|
||||||
|
if (image[i].includes('[embedImage:')) {
|
||||||
|
image = image[i].replace('[embedImage:', '').slice(0, -1);
|
||||||
|
text = text.replace(/(\[embedimage:.*?])/g, '');
|
||||||
|
i = image.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.includes('[embedThumbnail:')) {
|
||||||
|
thumbnail = text.split(/(\[embedThumbnail:.*?])/);
|
||||||
|
|
||||||
|
for (let i = 0, l = thumbnail.length; i < l; i++) {
|
||||||
|
if (thumbnail[i].includes('[embedThumbnail:')) {
|
||||||
|
thumbnail = thumbnail[i].replace('[embedThumbnail:', '').slice(0, -1);
|
||||||
|
text = text.replace(/(\[embedThumbnail:.*?])/g, '');
|
||||||
|
i = thumbnail.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.includes('[embedColor:')) {
|
||||||
|
color = text.split(/(\[embedColor:.*?])/);
|
||||||
|
for (let i = 0, l = color.length; i < l; i++) {
|
||||||
|
if (color[i].includes('[embedColor:')) {
|
||||||
|
color = color[i].replace('[embedColor:', '').slice(0, -1);
|
||||||
|
text = text.replace(/(\[embedColor:.*?])/g, '');
|
||||||
|
i = color.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (text.includes('[embedTitle:')) {
|
||||||
|
title = text.split(/(\[embedTitle:.*?])/);
|
||||||
|
for (let i = 0, l = title.length; i < l; i++) {
|
||||||
|
if (title[i].includes('[embedTitle:')) {
|
||||||
|
title = title[i].replace('[embedTitle:', '').slice(0, -1);
|
||||||
|
text = text.replace(/(\[embedTitle:.*?])/g, '');
|
||||||
|
i = title.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.includes('[embedFooter:')) {
|
||||||
|
footer = text.split(/(\[embedFooter:.*?])/);
|
||||||
|
for (let i = 0, l = footer.length; i < l; i++) {
|
||||||
|
if (footer[i].includes('[embedFooter:')) {
|
||||||
|
footer = footer[i].replace('[embedFooter:', '').slice(0, -1);
|
||||||
|
text = text.replace(/(\[embedFooter:.*?])/g, '');
|
||||||
|
i = footer.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.includes('[embedDesc:')) {
|
||||||
|
desc = text.split(/(\[embedDesc:.*?])/);
|
||||||
|
for (let i = 0, l = desc.length; i < l; i++) {
|
||||||
|
if (desc[i].includes('[embedDesc:')) {
|
||||||
|
desc = desc[i].replace('[embedDesc:', '').slice(0, -1);
|
||||||
|
i = desc.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const embed = new MessageEmbed()
|
||||||
|
.setColor(color)
|
||||||
|
.setTitle(title)
|
||||||
|
.setImage(image)
|
||||||
|
.setThumbnail(thumbnail)
|
||||||
|
.setDescription(desc)
|
||||||
|
.setFooter(footer)
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
if (attach) {
|
||||||
|
if (args.delete)
|
||||||
|
message.delete();
|
||||||
|
return message.channel.send(embed, {files: [attach]});
|
||||||
|
} else {
|
||||||
|
if (args.delete)
|
||||||
|
message.delete();
|
||||||
|
return message.channel.send(embed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the final text
|
||||||
|
if (attach) {
|
||||||
|
if (message.util.parsed.alias == 'sayd')
|
||||||
|
if (message.channel.permissionsFor(this.client.user).has('MANAGE_MESSAGES'))
|
||||||
|
message.delete();
|
||||||
|
else
|
||||||
|
message.channel.send('Im missing he `MANAGE_MESSAGES` perm to delete your message!');
|
||||||
|
|
||||||
|
return message.channel.send(text, {files: [attach]});
|
||||||
|
} else {
|
||||||
|
if (message.util.parsed.alias == 'sayd')
|
||||||
|
if (message.channel.permissionsFor(this.client.user).has('MANAGE_MESSAGES'))
|
||||||
|
message.delete();
|
||||||
|
else
|
||||||
|
message.channel.send('Im missing he `MANAGE_MESSAGES` perm to delete your message!');
|
||||||
|
return message.channel.send(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SayCommand;
|