1 |
import { Buildable, Command } from "@framework/commands/Command"; |
2 |
import InteractionContext from "@framework/commands/InteractionContext"; |
3 |
import LegacyContext from "@framework/commands/LegacyContext"; |
4 |
import { GatewayEventListener } from "@framework/events/GatewayEventListener"; |
5 |
import { HasEventListeners } from "@framework/types/HasEventListeners"; |
6 |
import { getAxiosClient } from "@sudobot/utils/axios"; |
7 |
import { |
8 |
ApplicationCommandOptionChoiceData, |
9 |
ChatInputCommandInteraction, |
10 |
type Interaction |
11 |
} from "discord.js"; |
12 |
|
13 |
export default class AnimeCommand extends Command implements HasEventListeners { |
14 |
public override readonly name = "anime"; |
15 |
public override readonly description = "Fetch a random anime waifu image."; |
16 |
public override readonly permissions = []; |
17 |
public override readonly defer = true; |
18 |
private readonly validCategories = [ |
19 |
"waifu", |
20 |
"neko", |
21 |
"shinobu", |
22 |
"megumin", |
23 |
"bully", |
24 |
"cuddle", |
25 |
"cry", |
26 |
"hug", |
27 |
"awoo", |
28 |
"kiss", |
29 |
"lick", |
30 |
"pat", |
31 |
"smug", |
32 |
"bonk", |
33 |
"yeet", |
34 |
"blush", |
35 |
"smile", |
36 |
"wave", |
37 |
"highfive", |
38 |
"handhold", |
39 |
"nom", |
40 |
"bite", |
41 |
"glomp", |
42 |
"slap", |
43 |
"kill", |
44 |
"kick", |
45 |
"happy", |
46 |
"wink", |
47 |
"poke", |
48 |
"dance", |
49 |
"cringe" |
50 |
]; |
51 |
|
52 |
public override build(): Buildable[] { |
53 |
return [ |
54 |
this.buildChatInput().addStringOption(option => |
55 |
option |
56 |
.setName("category") |
57 |
.setDescription("The category of the image to fetch.") |
58 |
.setRequired(true) |
59 |
.setAutocomplete(true) |
60 |
) |
61 |
]; |
62 |
} |
63 |
|
64 |
@GatewayEventListener("interactionCreate") |
65 |
public async onInteractionCreate(interaction: Interaction) { |
66 |
if (!interaction.isAutocomplete() || interaction.commandName !== this.name) { |
67 |
return; |
68 |
} |
69 |
|
70 |
const query = interaction.options.getString("category", true); |
71 |
const results: ApplicationCommandOptionChoiceData[] = []; |
72 |
|
73 |
for (const category of this.validCategories) { |
74 |
if (results.length >= 25) { |
75 |
break; |
76 |
} |
77 |
|
78 |
if (category.startsWith(query.toLowerCase())) { |
79 |
results.push({ |
80 |
name: category[0].toUpperCase() + category.slice(1), |
81 |
value: category |
82 |
}); |
83 |
} |
84 |
} |
85 |
|
86 |
await interaction.respond(results); |
87 |
} |
88 |
|
89 |
public override async execute( |
90 |
context: LegacyContext | InteractionContext<ChatInputCommandInteraction> |
91 |
) { |
92 |
const category = ( |
93 |
context.isLegacy() ? context.args[0] : context.options.getString("category", true) |
94 |
)?.toLowerCase(); |
95 |
|
96 |
if (!category || !this.validCategories.includes(category)) { |
97 |
return void (await context.reply( |
98 |
`Please provide a valid category. Valid categories are: ${this.validCategories.join(", ")}` |
99 |
)); |
100 |
} |
101 |
|
102 |
const url = `https://api.waifu.pics/sfw/${category}`; |
103 |
|
104 |
try { |
105 |
const response = await getAxiosClient().get(url); |
106 |
|
107 |
if (response.status < 200 || response.status >= 300) { |
108 |
throw new Error("Invalid status code"); |
109 |
} |
110 |
|
111 |
try { |
112 |
await context.reply({ |
113 |
files: [ |
114 |
{ |
115 |
attachment: response.data.url |
116 |
} |
117 |
] |
118 |
}); |
119 |
} catch (error) { |
120 |
this.application.logger.error(error); |
121 |
await context.error("Failed to send image to this channel."); |
122 |
} |
123 |
} catch (error) { |
124 |
this.application.logger.error(error); |
125 |
await context.error("Failed to fetch image."); |
126 |
} |
127 |
} |
128 |
} |