mirror of
https://github.com/arthur-pbty/xiao.git
synced 2026-06-22 10:19:11 +02:00
Remove 15 commands, patreon and bot list stuff
This commit is contained in:
@@ -1,76 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const request = require('node-superfetch');
|
||||
const { oneLine } = require('common-tags');
|
||||
const { base64 } = require('../../util/Util');
|
||||
const { FACEPLUSPLUS_KEY, FACEPLUSPLUS_SECRET } = process.env;
|
||||
const emotions = ['anger', 'disgust', 'fear', 'happiness', 'neutral', 'sadness', 'surprise'];
|
||||
const emotionResponse = ['angry', 'disgusted', 'afraid', 'happy', 'uncaring', 'sad', 'surprised'];
|
||||
|
||||
module.exports = class FaceCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'face',
|
||||
group: 'analyze',
|
||||
memberName: 'face',
|
||||
description: 'Determines the race, gender, and age of a face.',
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 30
|
||||
},
|
||||
credit: [
|
||||
{
|
||||
name: 'Face++ Cognitive Services',
|
||||
url: 'https://www.faceplusplus.com/',
|
||||
reason: 'Face Detection API',
|
||||
reasonURL: 'https://www.faceplusplus.com/face-detection/'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'image',
|
||||
prompt: 'What face would you like to scan?',
|
||||
type: 'image-or-avatar'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { image }) {
|
||||
try {
|
||||
const face = await this.detect(image);
|
||||
if (!face) return msg.reply('There are no faces in this image.');
|
||||
if (face === 'size') return msg.reply('This image is too large.');
|
||||
const pronoun = face.gender.value === 'Male' ? 'He' : 'She';
|
||||
const emotion = emotionResponse[emotions.indexOf(
|
||||
emotions.slice(0).sort((a, b) => face.emotion[b] - face.emotion[a])[0]
|
||||
)];
|
||||
const smile = face.smile.value > face.smile.threshold;
|
||||
const beautyScore = face.gender.value === 'Male' ? face.beauty.female_score : face.beauty.male_score;
|
||||
return msg.reply(oneLine`
|
||||
I think this is a photo of a ${face.age.value} year old ${face.gender.value.toLowerCase()}.
|
||||
${pronoun} appears to be ${emotion}, and is ${smile ? 'smiling' : 'not smiling'}. I give this
|
||||
face a ${Math.round(beautyScore)} on the 1-100 beauty scale.
|
||||
${beautyScore > 50 ? beautyScore > 70 ? beautyScore > 90 ? 'Hot!' : 'Not bad.' : 'Not _too_ ugly.' : 'Uggggly!'}
|
||||
`);
|
||||
} catch (err) {
|
||||
if (err.status === 400) return msg.reply('There are no faces in this image.');
|
||||
if (err.status === 403) return msg.reply('Hold your horses! The command is overloaded! Try again soon.');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
|
||||
async detect(image) {
|
||||
const imgData = await request.get(image);
|
||||
if (Buffer.byteLength(imgData.body) >= 2e+6) return 'size';
|
||||
const { body } = await request
|
||||
.post('https://api-us.faceplusplus.com/facepp/v3/detect')
|
||||
.attach('image_base64', base64(imgData.body))
|
||||
.query({
|
||||
api_key: FACEPLUSPLUS_KEY,
|
||||
api_secret: FACEPLUSPLUS_SECRET,
|
||||
return_attributes: 'gender,age,smiling,emotion,ethnicity,beauty'
|
||||
});
|
||||
if (!body.faces || !body.faces.length) return null;
|
||||
return body.faces[0].attributes;
|
||||
}
|
||||
};
|
||||
@@ -7,8 +7,7 @@ module.exports = class CleverbotEndCommand extends Command {
|
||||
aliases: ['clevs-end', 'chat-end', 'end'],
|
||||
group: 'cleverbot',
|
||||
memberName: 'cleverbot-end',
|
||||
description: 'Ends the current Cleverbot chat.',
|
||||
patronOnly: true
|
||||
description: 'Ends the current Cleverbot chat.'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ module.exports = class CleverbotCommand extends Command {
|
||||
group: 'cleverbot',
|
||||
memberName: 'cleverbot',
|
||||
description: 'Starts a Cleverbot conversation.',
|
||||
patronOnly: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Cleverbot',
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const Docs = require('discord.js-docs');
|
||||
|
||||
module.exports = class DocstCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'docs',
|
||||
aliases: ['discord-js-docs', 'discord-js', 'djs', 'djs-docs'],
|
||||
group: 'code',
|
||||
memberName: 'docs',
|
||||
description: 'Searches the discord.js docs for your query.',
|
||||
clientPermissions: ['EMBED_LINKS'],
|
||||
args: [
|
||||
{
|
||||
key: 'query',
|
||||
prompt: 'What do you want to search the docs for?',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { query }) {
|
||||
const doc = await Docs.fetch('stable');
|
||||
const embed = doc.resolveEmbed(query);
|
||||
if (!embed) return msg.say('Could not find any results.');
|
||||
return msg.embed(embed);
|
||||
}
|
||||
};
|
||||
@@ -1,94 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const request = require('node-superfetch');
|
||||
const { createCanvas, loadImage } = require('canvas');
|
||||
const path = require('path');
|
||||
const { base64 } = require('../../util/Util');
|
||||
const { FACEPLUSPLUS_KEY, FACEPLUSPLUS_SECRET } = process.env;
|
||||
|
||||
module.exports = class AnimeEyesCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'anime-eyes',
|
||||
aliases: ['ani-eyes', 'manga-eyes'],
|
||||
group: 'edit-face',
|
||||
memberName: 'anime-eyes',
|
||||
description: 'Draws anime eyes onto the faces in an image.',
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 60
|
||||
},
|
||||
credit: [
|
||||
{
|
||||
name: 'Face++ Cognitive Services',
|
||||
url: 'https://www.faceplusplus.com/',
|
||||
reason: 'Face Detection API',
|
||||
reasonURL: 'https://www.faceplusplus.com/face-detection/'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'image',
|
||||
prompt: 'What face would you like to scan?',
|
||||
type: 'image-or-avatar'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { image }) {
|
||||
const leftEye = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'anime-eyes', 'left.png'));
|
||||
const rightEye = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'anime-eyes', 'right.png'));
|
||||
const imgData = await request.get(image);
|
||||
try {
|
||||
const faces = await this.detect(imgData);
|
||||
if (!faces) return msg.reply('There are no faces in this image.');
|
||||
if (faces === 'size') return msg.reply('This image is too large.');
|
||||
const base = await loadImage(imgData.body);
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(base, 0, 0);
|
||||
for (const face of faces) {
|
||||
const landmarks = face.landmark;
|
||||
const leftWidth = landmarks.left_eye_right_corner.x - landmarks.left_eye_left_corner.x;
|
||||
const leftRatio = leftWidth / leftEye.width;
|
||||
const leftHeight = leftEye.height * leftRatio;
|
||||
ctx.drawImage(
|
||||
leftEye,
|
||||
landmarks.left_eye_left_corner.x - (leftWidth * 0.25),
|
||||
landmarks.left_eye_left_corner.y - (leftHeight / 2) - (leftHeight * 0.25),
|
||||
leftWidth * 1.5,
|
||||
leftHeight * 1.5
|
||||
);
|
||||
const rightWidth = landmarks.right_eye_right_corner.x - landmarks.right_eye_left_corner.x;
|
||||
const rightRatio = rightWidth / rightEye.width;
|
||||
const rightHeight = rightEye.height * rightRatio;
|
||||
ctx.drawImage(
|
||||
rightEye,
|
||||
landmarks.right_eye_left_corner.x - (rightWidth * 0.25),
|
||||
landmarks.right_eye_left_corner.y - (rightHeight / 2) - (rightHeight * 0.25),
|
||||
rightWidth * 1.5,
|
||||
rightHeight * 1.5
|
||||
);
|
||||
}
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'anime-eyes.png' }] });
|
||||
} catch (err) {
|
||||
if (err.status === 400) return msg.reply('There are no faces in this image.');
|
||||
if (err.status === 403) return msg.reply('Hold your horses! The command is overloaded! Try again soon.');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
|
||||
async detect(imgData) {
|
||||
if (Buffer.byteLength(imgData.body) >= 2e+6) return 'size';
|
||||
const { body } = await request
|
||||
.post('https://api-us.faceplusplus.com/facepp/v3/detect')
|
||||
.attach('image_base64', base64(imgData.body))
|
||||
.query({
|
||||
api_key: FACEPLUSPLUS_KEY,
|
||||
api_secret: FACEPLUSPLUS_SECRET,
|
||||
return_landmark: 1
|
||||
});
|
||||
if (!body.faces || !body.faces.length) return null;
|
||||
return body.faces;
|
||||
}
|
||||
};
|
||||
@@ -1,88 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const request = require('node-superfetch');
|
||||
const { createCanvas, loadImage } = require('canvas');
|
||||
const path = require('path');
|
||||
const { base64 } = require('../../util/Util');
|
||||
const { FACEPLUSPLUS_KEY, FACEPLUSPLUS_SECRET } = process.env;
|
||||
|
||||
module.exports = class DannyDevitoCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'danny-devito',
|
||||
aliases: ['devito'],
|
||||
group: 'edit-face',
|
||||
memberName: 'danny-devito',
|
||||
description: 'Draws Danny Devito\'s face onto the faces in an image.',
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 60
|
||||
},
|
||||
credit: [
|
||||
{
|
||||
name: 'Danny DeVito',
|
||||
url: 'https://twitter.com/dannydevito',
|
||||
reason: 'Himself'
|
||||
},
|
||||
{
|
||||
name: 'Face++ Cognitive Services',
|
||||
url: 'https://www.faceplusplus.com/',
|
||||
reason: 'Face Detection API',
|
||||
reasonURL: 'https://www.faceplusplus.com/face-detection/'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'image',
|
||||
prompt: 'What face would you like to scan?',
|
||||
type: 'image-or-avatar'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { image }) {
|
||||
const danny = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'danny-devito.png'));
|
||||
const imgData = await request.get(image);
|
||||
try {
|
||||
const faces = await this.detect(imgData);
|
||||
if (!faces) return msg.reply('There are no faces in this image.');
|
||||
if (faces === 'size') return msg.reply('This image is too large.');
|
||||
const base = await loadImage(imgData.body);
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(base, 0, 0);
|
||||
for (const face of faces) {
|
||||
const landmarks = face.landmark;
|
||||
const width = landmarks.contour_right1.x - landmarks.contour_left1.x;
|
||||
const ratio = width / danny.width;
|
||||
const height = danny.height * ratio;
|
||||
ctx.drawImage(
|
||||
danny,
|
||||
landmarks.contour_left1.x - (width * 0.25),
|
||||
landmarks.contour_left1.y - (height / 2) - (height * 0.25),
|
||||
width * 1.5,
|
||||
height * 1.5
|
||||
);
|
||||
}
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'danny-devito.png' }] });
|
||||
} catch (err) {
|
||||
if (err.status === 400) return msg.reply('There are no faces in this image.');
|
||||
if (err.status === 403) return msg.reply('Hold your horses! The command is overloaded! Try again soon.');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
|
||||
async detect(imgData) {
|
||||
if (Buffer.byteLength(imgData.body) >= 2e+6) return 'size';
|
||||
const { body } = await request
|
||||
.post('https://api-us.faceplusplus.com/facepp/v3/detect')
|
||||
.attach('image_base64', base64(imgData.body))
|
||||
.query({
|
||||
api_key: FACEPLUSPLUS_KEY,
|
||||
api_secret: FACEPLUSPLUS_SECRET,
|
||||
return_landmark: 1
|
||||
});
|
||||
if (!body.faces || !body.faces.length) return null;
|
||||
return body.faces;
|
||||
}
|
||||
};
|
||||
@@ -1,102 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const { GuildEmoji } = require('discord.js');
|
||||
const request = require('node-superfetch');
|
||||
const { createCanvas, loadImage } = require('canvas');
|
||||
const twemoji = require('twemoji-parser');
|
||||
const { base64 } = require('../../util/Util');
|
||||
const { FACEPLUSPLUS_KEY, FACEPLUSPLUS_SECRET } = process.env;
|
||||
|
||||
module.exports = class EmojiFaceCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'emoji-face',
|
||||
aliases: ['emoji-f', 'e-face'],
|
||||
group: 'edit-face',
|
||||
memberName: 'emoji-face',
|
||||
description: 'Draws an emoji onto the faces in an image.',
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 60
|
||||
},
|
||||
credit: [
|
||||
{
|
||||
name: 'Face++ Cognitive Services',
|
||||
url: 'https://www.faceplusplus.com/',
|
||||
reason: 'Face Detection API',
|
||||
reasonURL: 'https://www.faceplusplus.com/face-detection/'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'emoji',
|
||||
prompt: 'What emoji do you want to draw?',
|
||||
type: 'default-emoji|custom-emoji'
|
||||
},
|
||||
{
|
||||
key: 'image',
|
||||
prompt: 'What face would you like to scan?',
|
||||
type: 'image-or-avatar'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { emoji, image }) {
|
||||
let emojiURL;
|
||||
if (emoji instanceof GuildEmoji) {
|
||||
emojiURL = emoji.url;
|
||||
} else {
|
||||
const parsed = twemoji.parse(emoji);
|
||||
if (!parsed.length || !parsed[0].url) return msg.reply('This emoji is not yet supported.');
|
||||
emojiURL = parsed[0].url;
|
||||
}
|
||||
const emojiData = await request.get(emojiURL);
|
||||
const emojiImg = await loadImage(emojiData.body);
|
||||
if (emojiURL.endsWith('svg')) {
|
||||
emojiImg.width *= 4;
|
||||
emojiImg.height *= 4;
|
||||
}
|
||||
const imgData = await request.get(image);
|
||||
try {
|
||||
const faces = await this.detect(imgData);
|
||||
if (!faces) return msg.reply('There are no faces in this image.');
|
||||
if (faces === 'size') return msg.reply('This image is too large.');
|
||||
const base = await loadImage(imgData.body);
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(base, 0, 0);
|
||||
for (const face of faces) {
|
||||
const landmarks = face.landmark;
|
||||
const width = landmarks.contour_right1.x - landmarks.contour_left1.x;
|
||||
const ratio = width / emojiImg.width;
|
||||
const height = emojiImg.height * ratio;
|
||||
ctx.drawImage(
|
||||
emojiImg,
|
||||
landmarks.contour_left1.x - (width * 0.25),
|
||||
landmarks.contour_left1.y - (height / 2) - (height * 0.25),
|
||||
width * 1.5,
|
||||
height * 1.5
|
||||
);
|
||||
}
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'emoji-face.png' }] });
|
||||
} catch (err) {
|
||||
if (err.status === 400) return msg.reply('There are no faces in this image.');
|
||||
if (err.status === 403) return msg.reply('Hold your horses! The command is overloaded! Try again soon.');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
|
||||
async detect(imgData) {
|
||||
if (Buffer.byteLength(imgData.body) >= 2e+6) return 'size';
|
||||
const { body } = await request
|
||||
.post('https://api-us.faceplusplus.com/facepp/v3/detect')
|
||||
.attach('image_base64', base64(imgData.body))
|
||||
.query({
|
||||
api_key: FACEPLUSPLUS_KEY,
|
||||
api_secret: FACEPLUSPLUS_SECRET,
|
||||
return_landmark: 1
|
||||
});
|
||||
if (!body.faces || !body.faces.length) return null;
|
||||
return body.faces;
|
||||
}
|
||||
};
|
||||
@@ -1,92 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const request = require('node-superfetch');
|
||||
const { createCanvas, loadImage } = require('canvas');
|
||||
const path = require('path');
|
||||
const { base64 } = require('../../util/Util');
|
||||
const { FACEPLUSPLUS_KEY, FACEPLUSPLUS_SECRET } = process.env;
|
||||
|
||||
module.exports = class EyesCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'eyes',
|
||||
group: 'edit-face',
|
||||
memberName: 'eyes',
|
||||
description: 'Draws emoji eyes onto the faces in an image.',
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 60
|
||||
},
|
||||
credit: [
|
||||
{
|
||||
name: 'Face++ Cognitive Services',
|
||||
url: 'https://www.faceplusplus.com/',
|
||||
reason: 'Face Detection API',
|
||||
reasonURL: 'https://www.faceplusplus.com/face-detection/'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'image',
|
||||
prompt: 'What face would you like to scan?',
|
||||
type: 'image-or-avatar'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { image }) {
|
||||
const eyes = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'eyes.png'));
|
||||
const imgData = await request.get(image);
|
||||
try {
|
||||
const faces = await this.detect(imgData);
|
||||
if (!faces) return msg.reply('There are no faces in this image.');
|
||||
if (faces === 'size') return msg.reply('This image is too large.');
|
||||
const base = await loadImage(imgData.body);
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(base, 0, 0);
|
||||
for (const face of faces) {
|
||||
const landmarks = face.landmark;
|
||||
const leftWidth = landmarks.left_eye_right_corner.x - landmarks.left_eye_left_corner.x;
|
||||
const leftRatio = leftWidth / eyes.width;
|
||||
const leftHeight = eyes.height * leftRatio;
|
||||
ctx.drawImage(
|
||||
eyes,
|
||||
landmarks.left_eye_left_corner.x - (leftWidth / 2),
|
||||
landmarks.left_eye_left_corner.y - (leftHeight / 2) - (leftHeight / 2),
|
||||
leftWidth * 2,
|
||||
leftHeight * 2
|
||||
);
|
||||
const rightWidth = landmarks.right_eye_right_corner.x - landmarks.right_eye_left_corner.x;
|
||||
const rightRatio = rightWidth / eyes.width;
|
||||
const rightHeight = eyes.height * rightRatio;
|
||||
ctx.drawImage(
|
||||
eyes,
|
||||
landmarks.right_eye_left_corner.x - (rightWidth / 2),
|
||||
landmarks.right_eye_left_corner.y - (rightHeight / 2) - (rightHeight / 2),
|
||||
rightWidth * 2,
|
||||
rightHeight * 2
|
||||
);
|
||||
}
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'eyes.png' }] });
|
||||
} catch (err) {
|
||||
if (err.status === 400) return msg.reply('There are no faces in this image.');
|
||||
if (err.status === 403) return msg.reply('Hold your horses! The command is overloaded! Try again soon.');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
|
||||
async detect(imgData) {
|
||||
if (Buffer.byteLength(imgData.body) >= 2e+6) return 'size';
|
||||
const { body } = await request
|
||||
.post('https://api-us.faceplusplus.com/facepp/v3/detect')
|
||||
.attach('image_base64', base64(imgData.body))
|
||||
.query({
|
||||
api_key: FACEPLUSPLUS_KEY,
|
||||
api_secret: FACEPLUSPLUS_SECRET,
|
||||
return_landmark: 1
|
||||
});
|
||||
if (!body.faces || !body.faces.length) return null;
|
||||
return body.faces;
|
||||
}
|
||||
};
|
||||
@@ -1,143 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const { MessageActionRow, MessageButton } = require('discord.js');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const { Util: { escapeMarkdown } } = require('discord.js');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { readFile } = require('fs/promises');
|
||||
const stories = fs.readdirSync(path.join(__dirname, '..', '..', 'assets', 'txt', 'kino'))
|
||||
.map(story => story.slice(3).replace('.txt', ''));
|
||||
|
||||
module.exports = class KinoCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'kino',
|
||||
aliases: ['kino-journey', 'kinos-journey', 'kino\'s-journey'],
|
||||
group: 'other',
|
||||
memberName: 'kino',
|
||||
description: 'Read various Kino\'s Journey fan stories by dragonfire535.',
|
||||
details: stripIndents`
|
||||
**Stories:**
|
||||
\`\`\`
|
||||
${stories.map((story, i) => `${i.toString().padStart(2, '0')}. ${story}`).join('\n')}
|
||||
\`\`\`
|
||||
`,
|
||||
credit: [
|
||||
{
|
||||
name: 'Kino\'s Journey',
|
||||
url: 'https://kinonotabi.com/',
|
||||
reason: 'Original Concept'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'story',
|
||||
prompt: stripIndents`
|
||||
What story do you want to read? You can type the number or the name.
|
||||
\`\`\`
|
||||
${stories.map((story, i) => `${i.toString().padStart(2, '0')}. ${story}`).join('\n')}
|
||||
\`\`\`
|
||||
`,
|
||||
type: 'string',
|
||||
validate: choice => {
|
||||
if (stories.some(story => choice.toLowerCase() === story.toLowerCase())) return true;
|
||||
const num = Number.parseInt(choice, 10);
|
||||
return Boolean(stories[num]);
|
||||
},
|
||||
parse: choice => {
|
||||
if (stories.some(story => choice.toLowerCase() === story.toLowerCase())) {
|
||||
return choice.toLowerCase();
|
||||
}
|
||||
const num = Number.parseInt(choice, 10);
|
||||
return stories[num].toLowerCase();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { story }) {
|
||||
const storyData = await this.generateStory(story);
|
||||
let i = 0;
|
||||
let end = false;
|
||||
const row = new MessageActionRow();
|
||||
row.addComponents(
|
||||
new MessageButton().setCustomId('prev').setLabel('Prev').setStyle('PRIMARY').setDisabled(true),
|
||||
new MessageButton().setCustomId('next').setLabel('Next').setStyle('PRIMARY'),
|
||||
new MessageButton().setCustomId('end').setLabel('End').setStyle('DANGER')
|
||||
);
|
||||
const initialMsg = await msg.say(stripIndents`
|
||||
Welcome to Kino's Journey!
|
||||
Press the "Next" button to go to the next page, and "Prev" to go back.
|
||||
Press "End" at any time to stop reading.
|
||||
`, { components: [row] });
|
||||
const filter = res => res.user.id === msg.author.id;
|
||||
const initialInteractions = await initialMsg.awaitMessageComponent({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (!initialInteractions.size) return initialMsg.edit('Maybe next time!', { components: [] });
|
||||
let choice = initialInteractions.first();
|
||||
if (choice.customId === 'end') return choice.update('Maybe next time!', { components: [] });
|
||||
while (!end) {
|
||||
if (i === 0) {
|
||||
row.components[0].setDisabled(true);
|
||||
} else {
|
||||
row.components[0].setDisabled(false);
|
||||
}
|
||||
const line = storyData[i];
|
||||
if (!line) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
await choice.update(stripIndents`
|
||||
**Page ${i + 1}/${storyData.length}**
|
||||
|
||||
${escapeMarkdown(line.trim())}
|
||||
`, { components: [row] });
|
||||
const interactions = await initialMsg.awaitMessageComponent({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!interactions.size) break;
|
||||
choice = interactions.first();
|
||||
if (choice.customId === 'next') {
|
||||
i++;
|
||||
} else if (choice.customId === 'prev') {
|
||||
i--;
|
||||
} else if (choice.customId === 'end') {
|
||||
break;
|
||||
} else {
|
||||
return initialMsg.edit('Maybe next time!', { components: [] });
|
||||
}
|
||||
}
|
||||
return choice.update('Thank you for reading this chapter of Kino\'s Journey!', { components: [] });
|
||||
}
|
||||
|
||||
async generateStory(file) {
|
||||
const filename = stories.find(story => story.toLowerCase() === file);
|
||||
const num = stories.indexOf(filename).toString().padStart(2, '0');
|
||||
const story = await readFile(path.join(__dirname, '..', '..', 'assets', 'txt', 'kino', `${num} ${filename}.txt`), {
|
||||
encoding: 'utf8'
|
||||
});
|
||||
const chunks = [];
|
||||
let currentChunk = '';
|
||||
for (const paragraph of story.split('\n\n')) {
|
||||
if (paragraph === '***' && currentChunk) {
|
||||
chunks.push(currentChunk);
|
||||
currentChunk = '***\n\n';
|
||||
continue;
|
||||
}
|
||||
currentChunk += paragraph;
|
||||
currentChunk += '\n\n';
|
||||
if (currentChunk.length > 1000) {
|
||||
chunks.push(currentChunk);
|
||||
currentChunk = '';
|
||||
}
|
||||
}
|
||||
chunks.push(currentChunk);
|
||||
return chunks;
|
||||
}
|
||||
};
|
||||
@@ -40,9 +40,6 @@ module.exports = class ClocCommand extends Command {
|
||||
[
|
||||
'--json',
|
||||
'--exclude-dir=node_modules',
|
||||
'--read-lang-def',
|
||||
path.join(__dirname, '..', '..', 'assets', 'txt', 'txt_definition.txt'),
|
||||
'--force-lang=TXT,txt',
|
||||
path.join(__dirname, '..', '..')
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const { stripIndents } = require('common-tags');
|
||||
|
||||
module.exports = class DonateCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'donate',
|
||||
aliases: ['paypal', 'patreon'],
|
||||
group: 'util-public',
|
||||
memberName: 'donate',
|
||||
description: 'Responds with the bot\'s donation links.',
|
||||
guarded: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'PayPal',
|
||||
url: 'https://www.paypal.com/us/home',
|
||||
reason: 'Donation Gathering'
|
||||
},
|
||||
{
|
||||
name: 'Patreon',
|
||||
url: 'https://www.patreon.com/',
|
||||
reason: 'Donation Gathering'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
run(msg) {
|
||||
if (this.client.patreon.patrons.includes(msg.author.id)) {
|
||||
return msg.say('🎉 You are already a patron. Enjoy your rewards!');
|
||||
}
|
||||
return msg.say(stripIndents`
|
||||
Contribute to development!
|
||||
<https://www.patreon.com/xiaodiscord>
|
||||
<https://paypal.me/dragonfire535>
|
||||
`);
|
||||
}
|
||||
};
|
||||
@@ -11,7 +11,7 @@ module.exports = class InfoCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'info',
|
||||
aliases: ['stats', 'uptime'],
|
||||
aliases: ['stats', 'uptime', 'prefix', 'invite'],
|
||||
group: 'util-public',
|
||||
memberName: 'info',
|
||||
description: 'Responds with detailed bot information.',
|
||||
@@ -22,6 +22,7 @@ module.exports = class InfoCommand extends Command {
|
||||
|
||||
run(msg) {
|
||||
const invite = this.client.generateInvite({ permissions: ['ADMINISTRATOR'], scopes: ['bot'] });
|
||||
const prefix = msg.guild ? msg.guild.commandPrefix : this.client.commandPrefix;
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x00AE86)
|
||||
.setFooter(copyright.join('\n'))
|
||||
@@ -31,7 +32,7 @@ module.exports = class InfoCommand extends Command {
|
||||
.addField('❯ Home Server',
|
||||
this.client.options.invite ? embedURL('Invite', this.client.options.invite) : 'None', true)
|
||||
.addField('❯ Invite', embedURL('Add Me', invite), true)
|
||||
.addField('❯ Donate', embedURL('Patreon', 'https://www.patreon.com/xiaodiscord'), true)
|
||||
.addField('❯ Prefix', prefix || 'None', true)
|
||||
.addField('❯ Memory Usage', `${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB`, true)
|
||||
.addField('❯ Uptime', moment.duration(this.client.uptime).format('d:hh:mm:ss'), true)
|
||||
.addField('❯ Version', `v${version}`, true)
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const permissions = require('../../assets/json/permissions');
|
||||
|
||||
module.exports = class InviteCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'invite',
|
||||
group: 'util-public',
|
||||
memberName: 'invite',
|
||||
description: 'Responds with the bot\'s invite links.',
|
||||
guarded: true
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
const invite = await this.client.generateInvite({ permissions });
|
||||
return msg.say(stripIndents`
|
||||
Invite me using this link:
|
||||
<${invite}>
|
||||
|
||||
Join my home server for support and announcements:
|
||||
${this.client.options.invite || 'Coming soon...'}
|
||||
`);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
|
||||
module.exports = class PrefixCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'prefix',
|
||||
group: 'util-public',
|
||||
memberName: 'prefix',
|
||||
description: 'Responds with the bot\'s command prefix.',
|
||||
guarded: true
|
||||
});
|
||||
}
|
||||
|
||||
run(msg) {
|
||||
const prefix = msg.guild ? msg.guild.commandPrefix : this.client.commandPrefix;
|
||||
return msg.reply(prefix ? `The command prefix is \`${prefix}\`.` : 'There is no command prefix.');
|
||||
}
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
|
||||
module.exports = class ForcePatronCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'force-patron',
|
||||
group: 'util',
|
||||
memberName: 'force-patron',
|
||||
description: 'Allows a user to use patron-only commands.',
|
||||
details: 'Only the bot owner(s) may use this command.',
|
||||
ownerOnly: true,
|
||||
guarded: true,
|
||||
args: [
|
||||
{
|
||||
key: 'target',
|
||||
prompt: 'Who do you want to allow? Use the ID.',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
run(msg, { target }) {
|
||||
if (this.client.patreon.isPatron(target)) return msg.say(`💸 \`${target}\` is already a patron.`);
|
||||
this.client.patreon.forced.push(target);
|
||||
this.client.patreon.exportForced();
|
||||
return msg.say(`💸 Allowed \`${target}\` to use patron-only commands.`);
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const { removeFromArray } = require('../../util/Util');
|
||||
|
||||
module.exports = class UnforcePatronCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'unforce-patron',
|
||||
group: 'util',
|
||||
memberName: 'unforce-patron',
|
||||
description: 'Disallows a user from using patron-only commands.',
|
||||
details: 'Only the bot owner(s) may use this command.',
|
||||
ownerOnly: true,
|
||||
guarded: true,
|
||||
args: [
|
||||
{
|
||||
key: 'target',
|
||||
prompt: 'Who do you want to disallow? Use the ID.',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
run(msg, { target }) {
|
||||
if (!this.client.patreon.isPatron(target)) return msg.say(`💸 \`${target}\` is not a patron.`);
|
||||
removeFromArray(this.client.patreon.forced, target);
|
||||
this.client.patreon.exportForced();
|
||||
return msg.say(`💸 Disallowed \`${target}\` from using patron-only commands.`);
|
||||
}
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
|
||||
module.exports = class WebhookCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'webhook',
|
||||
aliases: ['rin', 'rin-say'],
|
||||
group: 'util',
|
||||
memberName: 'webhook',
|
||||
description: 'Posts a message to the webhook defined in the bot owner\'s `process.env`.',
|
||||
details: 'Only the bot owner(s) may use this command.',
|
||||
ownerOnly: true,
|
||||
clientPermissions: ['MANAGE_MESSAGES'],
|
||||
args: [
|
||||
{
|
||||
key: 'content',
|
||||
prompt: 'What text would you like the webhook to say?',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { content }) {
|
||||
try {
|
||||
if (msg.guild && msg.deletable) await msg.delete();
|
||||
await this.client.webhook.send(content);
|
||||
return null;
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,141 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const path = require('path');
|
||||
const { list, reactIfAble } = require('../../util/Util');
|
||||
const sounds = require('../../assets/json/soundboard');
|
||||
const soundsChoice = sounds.map(sound => sound[sound.length - 1].replace(/\.mp3$/, ''));
|
||||
|
||||
module.exports = class SoundboardCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'soundboard',
|
||||
aliases: ['sound'],
|
||||
group: 'voice',
|
||||
memberName: 'soundboard',
|
||||
description: 'Plays a sound in a voice channel.',
|
||||
details: `**Sounds:** ${soundsChoice.join(', ')}`,
|
||||
guildOnly: true,
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 10
|
||||
},
|
||||
userPermissions: ['CONNECT', 'SPEAK'],
|
||||
credit: [
|
||||
{
|
||||
name: '07th Expansion',
|
||||
url: 'http://07th-expansion.net/',
|
||||
reason: 'Nipah Sound'
|
||||
},
|
||||
{
|
||||
name: 'UncleKornicob',
|
||||
url: 'http://soundbible.com/',
|
||||
reason: 'Alarm Sound',
|
||||
reasonURL: 'http://soundbible.com/1787-Annoying-Alarm-Clock.html'
|
||||
},
|
||||
{
|
||||
name: 'Mike Koenig',
|
||||
url: 'http://soundbible.com/',
|
||||
reason: 'Rooster Sound',
|
||||
reasonURL: 'http://soundbible.com/1218-Rooster-Crow.html'
|
||||
},
|
||||
{
|
||||
name: 'Mike Koenig',
|
||||
url: 'http://soundbible.com/',
|
||||
reason: 'Cow Sound',
|
||||
reasonURL: 'http://soundbible.com/1778-Cow-Moo.html'
|
||||
},
|
||||
{
|
||||
name: 'Cam Martinez',
|
||||
url: 'http://soundbible.com/',
|
||||
reason: 'Car Crash Sound',
|
||||
reasonURL: 'http://soundbible.com/1757-Car-Brake-Crash.html'
|
||||
},
|
||||
{
|
||||
name: 'Orange Free Sounds',
|
||||
url: 'http://www.orangefreesounds.com/',
|
||||
reason: 'Dun Dun Dun Sound',
|
||||
reasonURL: 'http://www.orangefreesounds.com/dun-dun-dun-sound-effect-brass/'
|
||||
},
|
||||
{
|
||||
name: 'Apple',
|
||||
url: 'https://www.apple.com/',
|
||||
reason: 'Cat Sound'
|
||||
},
|
||||
{
|
||||
name: 'GRSites',
|
||||
url: 'http://www.grsites.com/',
|
||||
reason: 'Laugh Track Sound',
|
||||
reasonURL: 'http://www.grsites.com/archive/sounds/category/8/'
|
||||
},
|
||||
{
|
||||
name: 'Jeopardy',
|
||||
url: 'https://www.jeopardy.com/',
|
||||
reason: 'Jeopardy Sound'
|
||||
},
|
||||
{
|
||||
name: '4Kids',
|
||||
url: 'https://www.4kidsentertainmentinc.com/',
|
||||
reason: 'Who\'s That Pokémon Sound'
|
||||
},
|
||||
{
|
||||
name: 'Over the Green Fields',
|
||||
url: 'https://asianwiki.com/Over_the_Green_Fields',
|
||||
reason: 'Sad Violin Sound'
|
||||
},
|
||||
{
|
||||
name: 'Valve',
|
||||
url: 'https://www.valvesoftware.com/en/',
|
||||
reasonURL: 'http://www.thinkwithportals.com/',
|
||||
reason: 'Slow Clap Sound'
|
||||
},
|
||||
{
|
||||
name: 'Microsoft',
|
||||
url: 'https://www.microsoft.com/en-us',
|
||||
reason: 'Windows Start Up and Windows Error Sounds'
|
||||
},
|
||||
{
|
||||
name: 'Star Wars',
|
||||
url: 'https://www.starwars.com/',
|
||||
reason: 'Hello There Sound'
|
||||
},
|
||||
{
|
||||
name: 'Rockstar Games',
|
||||
url: 'https://www.rockstargames.com/',
|
||||
reason: 'Here We Go Again Sound'
|
||||
},
|
||||
{
|
||||
name: 'KONOSUBA -God\'s blessing on this wonderful world!',
|
||||
url: 'http://konosuba.com/',
|
||||
reason: 'Explosion Sound'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'sound',
|
||||
prompt: `What sound do you want to play? Either ${list(soundsChoice, 'or')}.`,
|
||||
type: 'string',
|
||||
validate: sound => {
|
||||
const choice = sound.toLowerCase().replaceAll(' ', '-');
|
||||
if (soundsChoice.includes(choice)) return true;
|
||||
return `You provided an invalid sound. Please choose either ${list(soundsChoice, 'or')}.`;
|
||||
},
|
||||
parse: sound => {
|
||||
const choice = sound.toLowerCase().replaceAll(' ', '-');
|
||||
return sounds.find(snd => snd.includes(`${choice}.mp3`));
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { sound }) {
|
||||
const connection = this.client.dispatchers.get(msg.guild.id);
|
||||
if (!connection) {
|
||||
const usage = this.client.registry.commands.get('join').usage();
|
||||
return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`);
|
||||
}
|
||||
if (!connection.canPlay) return msg.reply('I am already playing audio in this server.');
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', ...sound));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
const Command = require('../../framework/Command');
|
||||
const request = require('node-superfetch');
|
||||
const { Readable } = require('stream');
|
||||
const { list, reactIfAble } = require('../../util/Util');
|
||||
const voices = require('../../assets/json/vocodes');
|
||||
const { LOADING_EMOJI_ID } = process.env;
|
||||
|
||||
module.exports = class VocodesCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'vocodes',
|
||||
aliases: ['vocode'],
|
||||
group: 'voice',
|
||||
memberName: 'vocodes',
|
||||
description: 'Speak text like a variety of famous figures.',
|
||||
details: `**Voices:** ${Object.keys(voices).join(', ')}`,
|
||||
guildOnly: true,
|
||||
throttling: {
|
||||
usages: 2,
|
||||
duration: 30
|
||||
},
|
||||
userPermissions: ['CONNECT', 'SPEAK'],
|
||||
credit: [
|
||||
{
|
||||
name: 'Vocodes',
|
||||
url: 'https://vo.codes/',
|
||||
reason: 'API'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'voice',
|
||||
prompt: `What voice do you want to use? Either ${list(Object.keys(voices), 'or')}.`,
|
||||
type: 'string',
|
||||
oneOf: Object.keys(voices),
|
||||
parse: voice => voices[voice.toLowerCase()]
|
||||
},
|
||||
{
|
||||
key: 'text',
|
||||
prompt: 'What text do you want to say?',
|
||||
type: 'string',
|
||||
max: 500
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { voice, text }) {
|
||||
const connection = this.client.dispatchers.get(msg.guild.id);
|
||||
if (!connection) {
|
||||
const usage = this.client.registry.commands.get('join').usage();
|
||||
return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`);
|
||||
}
|
||||
if (!connection.canPlay) return msg.reply('I am already playing audio in this server.');
|
||||
try {
|
||||
await reactIfAble(msg, this.client.user, LOADING_EMOJI_ID, '💬');
|
||||
const { body } = await request
|
||||
.post('https://mumble.stream/speak_spectrogram')
|
||||
.send({
|
||||
speaker: voice,
|
||||
text
|
||||
});
|
||||
connection.play(Readable.from([Buffer.from(body.audio_base64, 'base64')]));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
return null;
|
||||
} catch (err) {
|
||||
await reactIfAble(msg, this.client.user, '⚠️');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user