Skip to content

Commit

Permalink
feat: /user-settings speaker (#10)
Browse files Browse the repository at this point in the history
* chore: remove unused method

* chore: fixed `ICommand` typing

* feat: /user-settings speaker
  • Loading branch information
yuimarudev authored Feb 14, 2024
1 parent f2f7cc5 commit 81f5567
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 18 deletions.
11 changes: 8 additions & 3 deletions src/commands/dict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
APIApplicationCommandInteractionDataStringOption,
APIApplicationCommandInteractionDataSubcommandOption,
APIChatInputApplicationCommandInteraction,
APIInteractionGuildMember,
RESTPostAPIChatInputApplicationCommandsJSONBody,
} from "@discordjs/core";
import { transmute } from "../common/functions.js";
Expand Down Expand Up @@ -59,9 +60,13 @@ export default class Dict implements ICommand {
async run(
api: API,
i: NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
>,
"member",
APIInteractionGuildMember
>,
): Promise<unknown> {
const command = i.data.options?.[0];
Expand Down
13 changes: 10 additions & 3 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
import {
API,
APIChatInputApplicationCommandInteraction,
APIInteractionGuildMember,
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";
import { UserSettings } from "./userSetting.js";

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

export interface ICommand {
defition(): RESTPostAPIChatInputApplicationCommandsJSONBody;
run(
api: API,
i: NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
>,
"member",
APIInteractionGuildMember
>,
): Promise<unknown>;
}
11 changes: 8 additions & 3 deletions src/commands/ping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SlashCommandBuilder } from "@discordjs/builders";
import {
API,
APIChatInputApplicationCommandInteraction,
APIInteractionGuildMember,
MessageFlags,
RESTPostAPIChatInputApplicationCommandsJSONBody,
} from "@discordjs/core";
Expand All @@ -19,9 +20,13 @@ export default class Ping implements ICommand {
async run(
api: API,
i: NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
>,
"member",
APIInteractionGuildMember
>,
): Promise<unknown> {
return await api.interactions.editReply(i.application_id, i.token, {
Expand Down
106 changes: 106 additions & 0 deletions src/commands/userSetting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
SlashCommandBuilder,
SlashCommandStringOption,
SlashCommandSubcommandBuilder,
} from "@discordjs/builders";
import {
API,
APIApplicationCommandInteractionDataSubcommandOption,
APIApplicationCommandStringOption,
APIChatInputApplicationCommandInteraction,
APIInteractionGuildMember,
RESTPostAPIChatInputApplicationCommandsJSONBody,
} from "@discordjs/core";
import { transmute } from "../common/functions.js";
import { NonNullableByKey } from "../common/types.js";
import { prisma } from "../index.js";
import { voices } from "../synthesizer/index.js";
import { ICommand } from "./index.js";

export class UserSettings implements ICommand {
defition(): RESTPostAPIChatInputApplicationCommandsJSONBody {
return new SlashCommandBuilder()
.setName("user-settings")
.setDescription("ユーザー側の設定を変更します")
.addSubcommand(
new SlashCommandSubcommandBuilder()
.setName("speaker")
.setDescription("話者を設定します")
.addStringOption(
new SlashCommandStringOption()
.setName("speaker")
.setDescription("話者")
.setRequired(true)
.addChoices(
...Object.entries(voices).map((x) => {
return { name: x[0], value: x[1] };
}),
),
),
)
.toJSON();
}

async run(
api: API,
i: NonNullableByKey<
NonNullableByKey<
APIChatInputApplicationCommandInteraction,
"guild_id",
string
>,
"member",
APIInteractionGuildMember
>,
): Promise<unknown> {
const synthesizer = (await prisma.synthesizer.findFirst({
where: {
userId: i.member.user.id,
},
})) ?? {
pitch: 1.0,
speed: 1.0,
userId: i.member.user.id,
voice: "ja-JP-NanamiNeural",
};

const command = i.data.options?.[0];

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

if (command.name === "speaker") {
const speaker = command.options?.[0];

if (!transmute<APIApplicationCommandStringOption>(speaker))
throw "unreachable";

const old = synthesizer.voice;
synthesizer.voice = speaker.value;

await prisma.synthesizer.upsert({
create: synthesizer,
update: synthesizer,
where: { userId: i.member.user.id },
});

return await api.interactions.editReply(i.application_id, i.token, {
embeds: [
{
title: "話者を変更しました",
description: `話者を ${
Object.entries(voices).find((x) => x[1] === old)?.[0]
} から ${
Object.entries(voices).find((x) => x[1] === speaker.value)?.[0]
} へ変更しました`,
color: 0x00ff00,
},
],
});
}

throw "unreachable";
}
}
9 changes: 0 additions & 9 deletions src/synthesizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,4 @@ export default class Synthesizer {
baseURL(route: string) {
return `https://${this.region}.tts.speech.microsoft.com/cognitiveservices/${route}`;
}

toJSON() {
return JSON.stringify({
voice: this.voice,
speed: this.speed,
userId: this.userId,
pitch: this.pitch,
});
}
}

0 comments on commit 81f5567

Please sign in to comment.