feat: update sern and bonzify

This commit is contained in:
2023-02-03 21:23:34 +01:00
parent c6be2d9a87
commit 61c1605af2
9 changed files with 282 additions and 277 deletions

View File

@@ -18,6 +18,7 @@ export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
//alias : [],
description: 'no one will read this (i hope)',
options: [
{
name: 'heartlocket',

View File

@@ -0,0 +1,27 @@
import { commandModule, CommandType } from '@sern/handler';
import axios from 'axios';
import { AttachmentBuilder, BufferResolvable } from 'discord.js';
import { publish } from '../../plugins/publish.js';
import { Readable } from 'node:stream'
export default commandModule({
type: CommandType.CtxMsg,
plugins: [publish()],
execute: async (ctx) => {
await ctx.deferReply()
const text = ctx.targetMessage.content;
const encodedText = encodeURIComponent(text);
const url = `https://www.tetyys.com/SAPI4/SAPI4?text=${encodedText}&voice=Adult%20Male%20%232%2C%20American%20English%20(TruVoice)&pitch=140&speed=157`;
const request = await fetch(url).then(res => res.arrayBuffer())
const stream = new Readable();
stream._read = () => {};
stream.push(Buffer.from(new Uint8Array(request)));
stream.push(null)
const attachment = new AttachmentBuilder(stream, { name: 'bonzied.wav' })
await ctx.editReply({ files: [attachment] })
},
});

View File

@@ -41,10 +41,11 @@ interface MyDependencies extends Dependencies {
'@sern/client' : Singleton<Client>;
'@sern/logger' : Singleton<DefaultLogging>
}
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: root => root
.add({ '@sern/client': single(client) })
.add({ '@sern/logger': single(new DefaultLogging()) })
.upsert({ '@sern/logger': single(new DefaultLogging()) })
});
Sern.init({
commands: 'dist/commands',

52
package-lock.json generated
View File

@@ -13,7 +13,7 @@
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.14.0",
"@napi-rs/canvas": "^0.1.30",
"@sern/handler": "^2.1.1",
"@sern/handler": "^2.5.0",
"axios": "^1.1.3",
"country-flag-emoji": "^1.0.3",
"dayjs": "^1.11.6",
@@ -494,13 +494,13 @@
}
},
"node_modules/@sern/handler": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@sern/handler/-/handler-2.1.1.tgz",
"integrity": "sha512-yPWOgUvi+9et6fC2BxLyIes5zvOLgorXdpLmI84cN7K7NVpYA/kRj2Y0aqriYb2fOdlPeakptODJwabwDSBfZw==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@sern/handler/-/handler-2.5.0.tgz",
"integrity": "sha512-EU80KPWgAaX3xCId3qUlwDKxLJnTH4abCHBqPVkq04IL1xqPFO91HeU+vhQ6/HJxS+MOqqli1NO6T3lTcOESXQ==",
"dependencies": {
"iti": "^0.5.0",
"iti": "^0.6.0",
"rxjs": "^7.5.6",
"ts-pattern": "^4.0.2",
"ts-pattern": "^4.0.6",
"ts-results-es": "^3.5.0"
}
},
@@ -1790,8 +1790,9 @@
}
},
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"license": "BSD-2-Clause"
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
},
"node_modules/http-errors": {
"version": "2.0.0",
@@ -1921,9 +1922,9 @@
"dev": true
},
"node_modules/iti": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/iti/-/iti-0.5.0.tgz",
"integrity": "sha512-ZiwdEIhXAxyb6/+j2didONRa3q73y9h8oHMRXAIkXv7k851cm8H7fyZZyszr514TdzgoVQl7Z6hvsdTogjgc0w==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/iti/-/iti-0.6.0.tgz",
"integrity": "sha512-JqujcnAIF3pmzitjbT3acc0LkordU6oHBDvWeT6a25wvEVBddFX3DFx/p6YBwGX1TTFsyLgVZtwhGOknthC96A==",
"dependencies": {
"utility-types": "^3.10.0"
},
@@ -3190,8 +3191,9 @@
"dev": true
},
"node_modules/ts-pattern": {
"version": "4.0.5",
"license": "MIT"
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-4.1.3.tgz",
"integrity": "sha512-8beXMWTGEv1JfDjSxfNhe4uT5jKYdhmEUKzt4gZW9dmHlquq3b+IbEyA7vX9LjBfzHmvKnM4HiomAUCyaW2Pew=="
},
"node_modules/ts-results-es": {
"version": "3.5.0",
@@ -3696,13 +3698,13 @@
"integrity": "sha512-zZxymtVO6zeXVMPds+6d7gv/OfnCc25M1Z+7ZLB0oPmeMTPeRWVPQSS16oDJy5ZsyCOLj7M6mbZml5gWXcVRNw=="
},
"@sern/handler": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@sern/handler/-/handler-2.1.1.tgz",
"integrity": "sha512-yPWOgUvi+9et6fC2BxLyIes5zvOLgorXdpLmI84cN7K7NVpYA/kRj2Y0aqriYb2fOdlPeakptODJwabwDSBfZw==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@sern/handler/-/handler-2.5.0.tgz",
"integrity": "sha512-EU80KPWgAaX3xCId3qUlwDKxLJnTH4abCHBqPVkq04IL1xqPFO91HeU+vhQ6/HJxS+MOqqli1NO6T3lTcOESXQ==",
"requires": {
"iti": "^0.5.0",
"iti": "^0.6.0",
"rxjs": "^7.5.6",
"ts-pattern": "^4.0.2",
"ts-pattern": "^4.0.6",
"ts-results-es": "^3.5.0"
}
},
@@ -4632,7 +4634,9 @@
}
},
"http-cache-semantics": {
"version": "4.1.0"
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
},
"http-errors": {
"version": "2.0.0",
@@ -4715,9 +4719,9 @@
"dev": true
},
"iti": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/iti/-/iti-0.5.0.tgz",
"integrity": "sha512-ZiwdEIhXAxyb6/+j2didONRa3q73y9h8oHMRXAIkXv7k851cm8H7fyZZyszr514TdzgoVQl7Z6hvsdTogjgc0w==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/iti/-/iti-0.6.0.tgz",
"integrity": "sha512-JqujcnAIF3pmzitjbT3acc0LkordU6oHBDvWeT6a25wvEVBddFX3DFx/p6YBwGX1TTFsyLgVZtwhGOknthC96A==",
"requires": {
"utility-types": "^3.10.0"
}
@@ -5549,7 +5553,9 @@
}
},
"ts-pattern": {
"version": "4.0.5"
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-4.1.3.tgz",
"integrity": "sha512-8beXMWTGEv1JfDjSxfNhe4uT5jKYdhmEUKzt4gZW9dmHlquq3b+IbEyA7vX9LjBfzHmvKnM4HiomAUCyaW2Pew=="
},
"ts-results-es": {
"version": "3.5.0"

View File

@@ -36,7 +36,7 @@
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.14.0",
"@napi-rs/canvas": "^0.1.30",
"@sern/handler": "^2.1.1",
"@sern/handler": "^2.5.0",
"axios": "^1.1.3",
"country-flag-emoji": "^1.0.3",
"dayjs": "^1.11.6",

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
//@ts-nocheck
/**
* This is buttonConfirmation plugin, it runs confirmation prompt in the form of buttons.
* Note that you need to use edit/editReply in the command itself because we are already replying in the plugin!
@@ -19,7 +19,7 @@
* ```
*/
import { CommandType, EventPlugin, PluginType } from "@sern/handler";
import { CommandControlPlugin, CommandType, controller } from "@sern/handler";
import {
ActionRowBuilder,
ButtonBuilder,
@@ -27,81 +27,75 @@ import {
ComponentType,
} from "discord.js";
export function acceptingBirthday(
options?: Partial<ConfirmationOptions>
): EventPlugin<CommandType.Both> {
return {
type: PluginType.Event,
description: "Confirms",
async execute([ctx], controller) {
options = {
content: "Se va a guardar tu cumpleaños en la base de datos de Vinci.\nAceptas?",
denialMessage: "Ok pues...",
labels: ["No", "Sí"],
time: 60_000,
wrongUserResponse: "Esto no es para tí!",
...options,
};
export function acceptingBirthday(options?: Partial<ConfirmationOptions>) {
return CommandControlPlugin<CommandType.Both>(async (ctx, args) => {
options = {
content: "Se va a guardar tu cumpleaños en la base de datos de Vinci.\nAceptas?",
denialMessage: "Ok pues...",
labels: ["No", "Sí"],
time: 60_000,
wrongUserResponse: "Esto no es para tí!",
...options,
};
const buttons = options.labels!.map((l, i) => {
return new ButtonBuilder()
.setCustomId(l)
.setLabel(l)
.setStyle(
i === 0 ? ButtonStyle.Danger : ButtonStyle.Success
);
});
const sent = await ctx.reply({
content: options.content,
components: [
new ActionRowBuilder<ButtonBuilder>().setComponents(
buttons
),
],
ephemeral: true
});
const buttons = options.labels!.map((l, i) => {
return new ButtonBuilder()
.setCustomId(l)
.setLabel(l)
.setStyle(
i === 0 ? ButtonStyle.Danger : ButtonStyle.Success
);
});
const sent = await ctx.reply({
content: options.content,
components: [
new ActionRowBuilder<ButtonBuilder>().setComponents(
buttons
),
],
ephemeral: true
});
const collector = sent.createMessageComponentCollector({
componentType: ComponentType.Button,
filter: (i) => i.user.id === ctx.user.id,
time: options.time,
});
const collector = sent.createMessageComponentCollector({
componentType: ComponentType.Button,
filter: (i) => i.user.id === ctx.user.id,
time: options.time,
});
return new Promise((resolve) => {
collector.on("collect", async (i) => {
await i.update({ components: [] });
collector.stop();
if (i.customId === options!.labels![1]) {
resolve(controller.next());
return;
}
await i.editReply({
content: options?.denialMessage,
});
resolve(controller.stop());
return new Promise((resolve) => {
collector.on("collect", async (i) => {
await i.update({ components: [] });
collector.stop();
if (i.customId === options!.labels![1]) {
resolve(controller.next());
return;
}
await i.editReply({
content: options?.denialMessage,
});
resolve(controller.stop());
});
collector.on("end", async (c) => {
if (c.size) return;
buttons.forEach((b) => b.setDisabled());
await sent.edit({
components: [
new ActionRowBuilder<ButtonBuilder>().setComponents(
buttons
),
],
});
});
collector.on("ignore", async (i) => {
await i.reply({
content: options?.wrongUserResponse,
ephemeral: true,
});
collector.on("end", async (c) => {
if (c.size) return;
buttons.forEach((b) => b.setDisabled());
await sent.edit({
components: [
new ActionRowBuilder<ButtonBuilder>().setComponents(
buttons
),
],
});
});
},
};
collector.on("ignore", async (i) => {
await i.reply({
content: options?.wrongUserResponse,
ephemeral: true,
});
});
});
});
}
interface ConfirmationOptions {

View File

@@ -1,31 +1,29 @@
// @ts-nocheck
/**
* @author: @EvolutionX-10
* @version: 1.0.0
* @description: This is OwnerOnly plugin, it allows only bot owners to run the command, like eval.
* @license: MIT
* @example:
* This is OwnerOnly plugin, it allows only bot owners to run the command, like eval.
*
* @author @EvolutionX-10 [<@697795666373640213>]
* @version 1.0.0
* @example
* ```ts
* import { OwnerOnly } from "../path/to/your/plugin/folder";
* import { sernModule, CommandType } from "@sern/handler";
* export default sernModule<CommandType.Slash>([OwnerOnly()], {
* // your code
* import { ownerOnly } from "../plugins/ownerOnly";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ ownerOnly() ],
* execute: (ctx) => {
* //your code here
* }
* })
* ```
*/
import { CommandType, EventPlugin, PluginType } from "@sern/handler";
import { CommandType, CommandControlPlugin, controller } from "@sern/handler";
const ownerIDs = ["464397024247152640", "703974042700611634", '252679156465139722', '370918560446545922', '375984365181599744', '785836117630910485', '368107342140801025']; //! Fill your ID
export function ownerOnly(): EventPlugin<CommandType.Both> {
return {
type: PluginType.Event,
description: "Allows only bot owner to run command",
async execute(event, controller) {
const [ctx] = event;
if (ownerIDs.includes(ctx.user.id)) return controller.next();
//* If you want to reply when the command fails due to user not being owner, you can use following
await ctx.reply("**ERROR**: Sólo los administradores pueden correr este comando.");
return controller.stop(); //! Important: It stops the execution of command!
},
};
export function ownerOnly() {
return CommandControlPlugin<CommandType.Both>((ctx, args) => {
if (ownerIDs.includes(ctx.user.id)) return controller.next();
//* If you want to reply when the command fails due to user not being owner, you can use following
ctx.reply("**ERROR**: Sólo los administradores pueden correr este comando.");
return controller.stop(); //! Important: It stops the execution of command!
});
}

View File

@@ -18,9 +18,9 @@
* ```
*/
import {
CommandPlugin,
CommandInitPlugin,
CommandType,
PluginType,
controller,
SernOptionsData,
SlashCommand,
} from "@sern/handler";
@@ -29,148 +29,133 @@ import {
ApplicationCommandType,
PermissionResolvable,
} from "discord.js";
/**
* This is the dependency getter that is created from Sern.makeDependencies.
* import it here so that this plugin has access to your bot's dependencies
*/
import { useContainer } from "../index.js";
export function publish(
options?: PublishOptions
): CommandPlugin<
| CommandType.Slash
| CommandType.Both
| CommandType.CtxUser
| CommandType.CtxMsg
> {
return {
type: PluginType.Command,
description: "Manage Application Commands",
name: "slash-auto-publish",
async execute({ mod: module }, controller) {
// Users need to provide their own useContainer function.
const [client] = useContainer("@sern/client");
const defaultOptions = {
guildIds: [],
dmPermission: undefined,
defaultMemberPermissions: null,
};
export const CommandTypeRaw = {
[CommandType.Both]: ApplicationCommandType.ChatInput,
[CommandType.CtxUser]: ApplicationCommandType.User,
[CommandType.CtxMsg]: ApplicationCommandType.Message,
[CommandType.Slash]: ApplicationCommandType.ChatInput,
} as const;
options = { ...defaultOptions, ...options } as PublishOptions &
ValidPublishOptions;
let { defaultMemberPermissions, dmPermission, guildIds } =
options as unknown as ValidPublishOptions;
export function publish<
T extends
| CommandType.Both
| CommandType.Slash
| CommandType.CtxMsg
| CommandType.CtxUser
>(options?: PublishOptions) {
return CommandInitPlugin<T>(async ({ module }) => {
// Users need to provide their own useContainer function.
const [client] = useContainer("@sern/client");
const defaultOptions = {
guildIds: [],
dmPermission: undefined,
defaultMemberPermissions: null,
};
function c(e: unknown) {
console.error("publish command didnt work for", module.name);
console.error(e);
options = { ...defaultOptions, ...options } as PublishOptions &
ValidPublishOptions;
let { defaultMemberPermissions, dmPermission, guildIds } =
options as unknown as ValidPublishOptions;
function c(e: unknown) {
console.error("publish command didnt work for", module.name);
console.error(e);
}
const log =
(...message: any[]) =>
() =>
console.log(...message);
const logged = (...message: any[]) => log(message);
/**
* a local function that returns either one value or the other,
* depending on {t}'s CommandType. If the commandtype of
* this module is CommandType.Both or CommandType.Text or CommandType.Slash,
* return 'is', else return 'els'
* @param t
* @returns S | T
*/
const appCmd = <V extends CommandType, S, T>(t: V) => {
return (is: S, els: T) => ((t & CommandType.Both) !== 0 ? is : els);
};
const curAppType = CommandTypeRaw[module.type];
const createCommandData = () => {
const cmd = appCmd(module.type);
return {
name: module.name,
type: curAppType,
description: cmd(module.description, ""),
options: cmd(
optionsTransformer((module as SlashCommand).options ?? []),
[]
),
defaultMemberPermissions,
dmPermission,
} as ApplicationCommandData;
};
try {
const commandData = createCommandData();
if (!guildIds.length) {
const cmd = (await client.application!.commands.fetch()).find(
(c) => c.name === module.name && c.type === curAppType
);
if (cmd) {
if (!cmd.equals(commandData, true)) {
logged(
`Found differences in global command ${module.name}`
);
cmd.edit(commandData).then(
log(
`${module.name} updated with new data successfully!`
)
);
}
return controller.next();
}
client
.application!.commands.create(commandData)
.then(log("Command created", module.name))
.catch(c);
return controller.next();
}
const log =
(...message: any[]) =>
() =>
console.log(...message);
const logged = (...message: any[]) => log(message);
/**
* a local function that returns either one value or the other,
* depending on {t}'s CommandType. If the commandtype of
* this module is CommandType.Both or CommandType.Text or CommandType.Slash,
* return 'is', else return 'els'
* @param t
* @returns S | T
*/
const appCmd = <V extends CommandType, S, T>(t: V) => {
return (is: S, els: T) =>
(t & CommandType.Both) !== 0 ? is : els;
};
const curAppType = CommandTypeRaw[module.type];
const createCommandData = () => {
const cmd = appCmd(module.type);
return {
name: module.name,
type: curAppType,
description: cmd(module.description, ""),
options: cmd(
optionsTransformer(
(module as SlashCommand).options ?? []
),
[]
),
defaultMemberPermissions,
dmPermission,
} as ApplicationCommandData;
};
try {
const commandData = createCommandData();
if (!guildIds.length) {
const cmd = (
await client.application!.commands.fetch()
).find(
(c) => c.name === module.name && c.type === curAppType
);
if (cmd) {
if (!cmd.equals(commandData, true)) {
logged(
`Found differences in global command ${module.name}`
);
cmd.edit(commandData).then(
for (const id of guildIds) {
const guild = await client.guilds.fetch(id).catch(c);
if (!guild) continue;
const guildCmd = (await guild.commands.fetch()).find(
(c) => c.name === module.name && c.type === curAppType
);
if (guildCmd) {
if (!guildCmd.equals(commandData, true)) {
logged(`Found differences in command ${module.name}`);
guildCmd
.edit(commandData)
.then(
log(
`${module.name} updated with new data successfully!`
)
);
}
return controller.next();
}
client
.application!.commands.create(commandData)
.then(log("Command created", module.name))
.catch(c);
return controller.next();
}
for (const id of guildIds) {
const guild = await client.guilds.fetch(id).catch(c);
if (!guild) continue;
const guildCmd = (await guild.commands.fetch()).find(
(c) => c.name === module.name && c.type === curAppType
);
if (guildCmd) {
if (!guildCmd.equals(commandData, true)) {
logged(
`Found differences in command ${module.name}`
);
guildCmd
.edit(commandData)
.then(
log(
`${module.name} updated with new data successfully!`
)
)
.catch(c);
continue;
}
)
.catch(c);
continue;
}
guild.commands
.create(commandData)
.then(
log(
"Guild Command created",
module.name,
guild.name
)
)
.catch(c);
continue;
}
return controller.next();
} catch (e) {
logged("Command did not register" + module.name);
logged(e);
return controller.stop();
guild.commands
.create(commandData)
.then(log("Guild Command created", module.name, guild.name))
.catch(c);
}
},
};
return controller.next();
} catch (e) {
logged("Command did not register" + module.name);
logged(e);
return controller.stop();
}
});
}
export function optionsTransformer(ops: Array<SernOptionsData>) {
@@ -179,13 +164,6 @@ export function optionsTransformer(ops: Array<SernOptionsData>) {
);
}
export const CommandTypeRaw = {
[CommandType.Both]: ApplicationCommandType.ChatInput,
[CommandType.CtxUser]: ApplicationCommandType.Message,
[CommandType.CtxMsg]: ApplicationCommandType.User,
[CommandType.Slash]: ApplicationCommandType.ChatInput,
} as const;
export type NonEmptyArray<T extends `${number}` = `${number}`> = [T, ...T[]];
export interface ValidPublishOptions {
@@ -193,11 +171,13 @@ export interface ValidPublishOptions {
dmPermission: boolean;
defaultMemberPermissions: PermissionResolvable;
}
interface GuildPublishOptions {
guildIds?: NonEmptyArray;
defaultMemberPermissions?: PermissionResolvable;
dmPermission?: never;
}
interface GlobalPublishOptions {
defaultMemberPermissions?: PermissionResolvable;
dmPermission?: false;

View File

@@ -1,31 +1,29 @@
// @ts-nocheck
/**
* @author: @EvolutionX-10
* @version: 1.0.0
* @description: This is OwnerOnly plugin, it allows only bot owners to run the command, like eval.
* @license: MIT
* @example:
* This is OwnerOnly plugin, it allows only bot owners to run the command, like eval.
*
* @author @EvolutionX-10 [<@697795666373640213>]
* @version 1.0.0
* @example
* ```ts
* import { OwnerOnly } from "../path/to/your/plugin/folder";
* import { sernModule, CommandType } from "@sern/handler";
* export default sernModule<CommandType.Slash>([OwnerOnly()], {
* // your code
* import { ownerOnly } from "../plugins/ownerOnly";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ ownerOnly() ],
* execute: (ctx) => {
* //your code here
* }
* })
* ```
*/
import { CommandType, EventPlugin, PluginType } from "@sern/handler";
import { CommandType, CommandControlPlugin, controller } from "@sern/handler";
const ownerIDs = ['703974042700611634']; //! Fill your ID
export function srIzanOnly(): EventPlugin<CommandType.Both> {
return {
type: PluginType.Event,
description: "Allows only bot owner to run command",
async execute(event, controller) {
const [ctx] = event;
if (ownerIDs.includes(ctx.user.id)) return controller.next();
//* If you want to reply when the command fails due to user not being owner, you can use following
await ctx.reply("**ERROR**: Sólo Sr Izan puede correr este comando.");
return controller.stop(); //! Important: It stops the execution of command!
},
};
export function srIzanOnly() {
return CommandControlPlugin<CommandType.Both>((ctx, args) => {
if (ownerIDs.includes(ctx.user.id)) return controller.next();
//* If you want to reply when the command fails due to user not being owner, you can use following
ctx.reply("**ERROR**: Sólo Sr Izan puede correr este comando.");
return controller.stop(); //! Important: It stops the execution of command!
});
}