Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.717.0",
"@barudakrosul/textwrap": "^0.0.4",
"@octokit/rest": "^21.0.2",
"@t3-oss/env-core": "^0.11.1",
"@types/sharp": "^0.32.0",
"bufferutil": "^4.0.8",
"cowsay": "^1.6.0",
"dayjs": "^1.11.13",
"discord.js": "^14.16.3",
"fastest-levenshtein": "^1.0.16",
Expand Down
98 changes: 98 additions & 0 deletions src/commands/cowsay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import {
type ChatInputCommandInteraction,
SlashCommandBuilder,
} from "discord.js";
import cowsay from "cowsay";
import textwrap from "@barudakrosul/textwrap";

const DEFAULT_WRAP_WIDTH = 40;

export const data = new SlashCommandBuilder()
.setName("cowsay")
.setDescription("Make a cow say it")
.addStringOption((option) =>
option
.setName("text")
.setDescription("The text to say")
.setRequired(true),
)
.addStringOption((option) =>
option
.setName("cow")
.setDescription("The cow design to use")
.setRequired(false),
)
.addIntegerOption((option) =>
option
.setName("wrap_width")
.setDescription(
"Width at which to wrap the input text (0 to disable)",
)
.setRequired(false),
);

export async function command(interaction: ChatInputCommandInteraction) {
const { options } = interaction;

const text = options.getString("text", true);
const cow = options.getString("cow");
const wrapWidth = options.getInteger("wrap_width") ?? DEFAULT_WRAP_WIDTH;

const isChannel = !!interaction.channel;

if (!isChannel) {
await interaction.reply({
content: "This command can only be used in a channel",
ephemeral: true,
});
return;
}

if (text === "!list") {
for (const chunk of await getCowListResponseContent()) {
await interaction.reply({
content: chunk,
ephemeral: true,
});
}
} else {
await interaction.reply({
content: getCowsayResponseContent(text, cow, wrapWidth),
});
}
}

function getCowsayResponseContent(
text: string,
cow: string | null,
wrapWidth: number,
): string {
const wrappedText =
wrapWidth > 0 ? textwrap.wrap(text, wrapWidth).join("\n") : text;
const cowsaid = cowsay.say({
text: wrappedText,
f: cow ?? undefined,
});
return "```\n" + cowsaid + "\n```";
}

async function getCowListResponseContent(): Promise<string[]> {
try {
const filenames = await cowsay.list(() => {});
const cows = filenames.map((name) => name.replace(/\.cow$/, ""));
const chunks = ["```\n"];
for (const cow of cows) {
if (chunks[chunks.length - 1].length + cow.length + 1 + 3 > 2000) {
chunks[chunks.length - 1] += "```";
chunks.push("```\n");
}
chunks[chunks.length - 1] += cow + "\n";
}
chunks[chunks.length - 1] += "```";
return chunks;
} catch (e) {
const msg = (e as Error).message;
console.error(`Error listing cows: ${msg}`);
return ["Error listing cows"];
}
}
3 changes: 2 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import type {
} from "discord.js";

import * as summarize from "./summarize";
import * as cowsay from "./cowsay";

type Command = {
data: SlashCommandOptionsOnlyBuilder;
command: (interaction: ChatInputCommandInteraction) => Promise<void>;
};

export const commands: Command[] = [summarize];
export const commands: Command[] = [summarize, cowsay];