Skip to content

Commit

Permalink
feat: add server dictionary (#3)
Browse files Browse the repository at this point in the history
* feat: /dict put

* feat: add /dict delete

* feat: replace content on `speak()`

* fix: Invalid `prisma.dictionary.upsert()` invocation
  • Loading branch information
yuimarudev authored Feb 10, 2024
1 parent b701074 commit 46bcdd0
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 4 deletions.
11 changes: 11 additions & 0 deletions prisma/migrations/20240210161849_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
Warnings:
- A unique constraint covering the columns `[guildId,word]` on the table `Dictionary` will be added. If there are existing duplicate values, this will fail.
*/
-- DropIndex
DROP INDEX "Dictionary_word_key";

-- CreateIndex
CREATE UNIQUE INDEX "Dictionary_guildId_word_key" ON "Dictionary"("guildId", "word");
4 changes: 3 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ model Synthesizer {
model Dictionary {
id Int @id @default(autoincrement())
guildId String
word String @unique
word String
read String
@@unique([guildId, word])
}
138 changes: 138 additions & 0 deletions src/commands/dict.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import {
SlashCommandBuilder,
SlashCommandStringOption,
SlashCommandSubcommandBuilder,
} from "@discordjs/builders";
import {
API,
APIApplicationCommandInteractionDataStringOption,
APIApplicationCommandInteractionDataSubcommandOption,
APIChatInputApplicationCommandInteraction,
RESTPostAPIChatInputApplicationCommandsJSONBody,
} from "@discordjs/core";
import { transmute } from "../common/functions.js";
import { NonNullableByKey } from "../common/types.js";
import { prisma } from "../index.js";
import { ICommand } from "./index.js";

export default class Dict implements ICommand {
defition(): RESTPostAPIChatInputApplicationCommandsJSONBody {
return new SlashCommandBuilder()
.setName("dict")
.setDescription("ユーザー辞書に関する操作を行います")
.addSubcommand(
new SlashCommandSubcommandBuilder()
.setName("put")
.setDescription("サーバーの辞書を追加・編集します")
.addStringOption(
new SlashCommandStringOption()
.setName("word")
.setDescription("単語")
.setRequired(true),
)
.addStringOption(
new SlashCommandStringOption()
.setName("read")
.setDescription("読み")
.setRequired(true),
),
)
.addSubcommand(
new SlashCommandSubcommandBuilder()
.setName("delete")
.setDescription("サーバーの辞書を削除します")
.addStringOption(
new SlashCommandStringOption()
.setName("word")
.setDescription("単語")
.setRequired(true),
),
)
.toJSON();
}

async run(
api: API,
i: NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
>,
): Promise<unknown> {
const command = i.data.options?.[0];

if (
!transmute<APIApplicationCommandInteractionDataSubcommandOption>(command)
)
return;

if (command.name === "put") {
const word = command.options?.find((x) => x.name === "word");
const read = command.options?.find((x) => x.name === "read");

if (
!transmute<APIApplicationCommandInteractionDataStringOption>(word) ||
!transmute<APIApplicationCommandInteractionDataStringOption>(read)
)
return;

await prisma.dictionary.upsert({
create: { guildId: i.guild_id, read: read.value, word: word.value },
update: { read: read.value },
where: {
guildId: i.guild_id,
word: word.value,
guildId_word: { guildId: i.guild_id, word: word.value },
},
});

return await api.interactions.editReply(i.application_id, i.token, {
embeds: [
{
title: "辞書を編集しました",
description: `単語: \`${word?.value}\`
読み: \`${read?.value}\``,
color: 0x00ff00,
},
],
});
}

if (command.name === "delete") {
const word = command.options?.find((x) => x.name === "word");

if (!transmute<APIApplicationCommandInteractionDataStringOption>(word))
return;

const dict = await prisma.dictionary.findFirst({
where: { guildId: i.guild_id, word: word.value },
});

if (!dict)
return await api.interactions.editReply(i.application_id, i.token, {
embeds: [
{
title: "エラーです",
description: "単語が存在しません",
color: 0xff0000,
},
],
});

await prisma.dictionary.delete({ where: { id: dict.id } });

return await api.interactions.editReply(i.application_id, i.token, {
embeds: [
{
title: "辞書を削除しました",
description: `単語: \`${dict.word}\`
読み: \`${dict.read}\``,
color: 0x00ff00,
},
],
});
}

throw "unreachable";
}
}
8 changes: 7 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ import {
RESTPostAPIChatInputApplicationCommandsJSONBody,
} from "@discordjs/core";
import { NonNullableByKey } from "../common/types.js";
import Dict from "./dict.js";
import Join from "./join.js";
import Leave from "./leave.js";
import Ping from "./ping.js";

export const commands: ICommand[] = [new Ping(), new Join(), new Leave()];
export const commands: ICommand[] = [
new Ping(),
new Join(),
new Leave(),
new Dict(),
];

export interface ICommand {
defition(): RESTPostAPIChatInputApplicationCommandsJSONBody;
Expand Down
14 changes: 12 additions & 2 deletions src/voice/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ export default class Room {
roomManager.delete(this.guildId);
}

async speak(message: APIMessage) {
async speak(message: APIMessage & { guild_id: string }) {
const release = await this.audioResourceLock.acquire();

try {
const userConfig = await prisma.synthesizer.findFirst({
where: { userId: message.author.id },
});
const dictionaries = await prisma.dictionary.findMany({
where: { guildId: message.guild_id },
});
const synthesizer = new Synthesizer(
except(process.env["key"]),
except(process.env["region"]),
Expand All @@ -69,9 +72,16 @@ export default class Room {
userConfig?.pitch ?? 1,
userConfig?.speed ?? 1,
);

let content = cleanContent(message);

for (const dict of dictionaries) {
content = content.replaceAll(dict.word, dict.read);
}

const resource = createAudioResource(
Readable.fromWeb(
(await synthesizer.synthesis(cleanContent(message))) ||
(await synthesizer.synthesis(content)) ||
(() => {
throw "fuck";
})(),
Expand Down

0 comments on commit 46bcdd0

Please sign in to comment.