update crates, fix event_handler, main

This commit is contained in:
mii443
2025-03-30 23:34:25 +09:00
parent 68e96ef784
commit df46152a12
3 changed files with 236 additions and 284 deletions

View File

@ -21,11 +21,11 @@ version = "0.8"
features = ["serde", "v4"]
[dependencies.songbird]
version = "0.3.2"
version = "0.5"
features = ["builtin-queue"]
[dependencies.serenity]
version = "0.11.5"
version = "0.12"
features = ["builder", "cache", "client", "gateway", "model", "utils", "unstable_discord_api", "collector", "rustls_backend", "framework", "voice"]

View File

@ -8,18 +8,9 @@ use crate::{
tts::tts_type::TTSType,
};
use serenity::{
async_trait,
client::{Context, EventHandler},
model::{
channel::Message,
gateway::Ready,
prelude::{
component::{ActionRowComponent, ButtonStyle, InputTextStyle},
interaction::{Interaction, InteractionResponseType, MessageFlags},
ChannelType,
},
voice::VoiceState,
},
all::{ActionRowComponent, ButtonStyle, ComponentInteractionDataKind, CreateActionRow, CreateButton, CreateEmbed, CreateInputText, CreateInteractionResponse, CreateInteractionResponseMessage, CreateModal, CreateSelectMenu, CreateSelectMenuKind, CreateSelectMenuOption, InputTextStyle, MessageFlags}, async_trait, client::{Context, EventHandler}, model::{
application::Interaction, channel::Message, gateway::Ready, prelude::ChannelType, voice::VoiceState
}
};
pub struct Handler;
@ -35,7 +26,7 @@ impl EventHandler for Handler {
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
if let Interaction::ApplicationCommand(command) = interaction.clone() {
if let Interaction::Command(command) = interaction.clone() {
let name = &*command.data.name;
match name {
"setup" => setup_command(&ctx, &command).await.unwrap(),
@ -45,7 +36,7 @@ impl EventHandler for Handler {
_ => {}
}
}
if let Interaction::ModalSubmit(modal) = interaction.clone() {
if let Interaction::Modal(modal) = interaction.clone() {
if modal.data.custom_id != "TTS_CONFIG_SERVER_ADD_DICTIONARY" {
return;
}
@ -53,19 +44,19 @@ impl EventHandler for Handler {
let rows = modal.data.components.clone();
let rule_name =
if let ActionRowComponent::InputText(text) = rows[0].components[0].clone() {
text.value
text.value.unwrap()
} else {
panic!("Cannot get rule name");
};
let from = if let ActionRowComponent::InputText(text) = rows[1].components[0].clone() {
text.value
text.value.unwrap()
} else {
panic!("Cannot get from");
};
let to = if let ActionRowComponent::InputText(text) = rows[2].components[0].clone() {
text.value
text.value.unwrap()
} else {
panic!("Cannot get to");
};
@ -86,7 +77,7 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.get_server_config_or_default(modal.guild_id.unwrap().0)
.get_server_config_or_default(modal.guild_id.unwrap().get())
.await
.unwrap()
.unwrap()
@ -100,20 +91,14 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.set_server_config(modal.guild_id.unwrap().0, config)
.set_server_config(modal.guild_id.unwrap().get(), config)
.await
.unwrap();
modal
.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.custom_id("TTS_CONFIG_SERVER_ADD_DICTIONARY_RESPONSE")
.content(format!(
.create_response(&ctx.http, CreateInteractionResponse::UpdateMessage(CreateInteractionResponseMessage::new().content(format!(
"辞書を追加しました\n名前: {}\n変換元: {}\n変換後: {}",
rule_name, from, to
))
})
})
))))
.await
.unwrap();
}
@ -121,7 +106,12 @@ impl EventHandler for Handler {
if let Some(message_component) = interaction.message_component() {
match &*message_component.data.custom_id {
"TTS_CONFIG_SERVER_REMOVE_DICTIONARY_MENU" => {
let i = usize::from_str_radix(&message_component.data.values[0], 10).unwrap();
let i = usize::from_str_radix(match message_component.data.kind {
ComponentInteractionDataKind::StringSelect { values, .. } => {
&values[0].clone()
}
_ => panic!("Cannot get index"),
}, 10).unwrap();
let data_read = ctx.data.read().await;
let mut config = {
@ -131,7 +121,7 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.get_server_config_or_default(message_component.guild_id.unwrap().0)
.get_server_config_or_default(message_component.guild_id.unwrap().get())
.await
.unwrap()
.unwrap()
@ -145,20 +135,14 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.set_server_config(message_component.guild_id.unwrap().0, config)
.set_server_config(message_component.guild_id.unwrap().get(), config)
.await
.unwrap();
}
message_component
.create_interaction_response(&ctx, |f| {
f.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.custom_id("DICTIONARY_REMOVED")
.content("辞書を削除しました")
.components(|c| c)
})
})
.create_response(&ctx,
CreateInteractionResponse::UpdateMessage(CreateInteractionResponseMessage::new().content("辞書を削除しました")))
.await
.unwrap();
}
@ -172,51 +156,46 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.get_server_config_or_default(message_component.guild_id.unwrap().0)
.get_server_config_or_default(message_component.guild_id.unwrap().get())
.await
.unwrap()
.unwrap()
};
message_component
.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.custom_id("TTS_CONFIG_SERVER_REMOVE_DICTIONARY")
.create_response(&ctx.http,
CreateInteractionResponse::UpdateMessage(
CreateInteractionResponseMessage::new()
.content("削除する辞書内容を選択してください")
.components(|c| {
c.create_action_row(|a| {
a.create_select_menu(|s| {
s.custom_id(
.components(vec![
CreateActionRow::SelectMenu(
CreateSelectMenu::new(
"TTS_CONFIG_SERVER_REMOVE_DICTIONARY_MENU",
)
.options(|o| {
let mut o = o;
CreateSelectMenuKind::String {
options: {
let mut options = vec![];
for (i, rule) in config
.dictionary
.rules
.iter()
.enumerate()
{
o = o.create_option(|c| {
c.label(rule.id.clone())
.value(i)
.description(format!(
let option = CreateSelectMenuOption::new(rule.id.clone(), i.to_string());
option.description(format!(
"{} -> {}",
rule.rule.clone(),
rule.to.clone()
))
});
));
options.push(option);
}
options
}
o
})
.max_values(1)
.min_values(0)
})
})
})
})
})
)
])
))
.await
.unwrap();
}
@ -229,78 +208,81 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.get_server_config_or_default(message_component.guild_id.unwrap().0)
.get_server_config_or_default(message_component.guild_id.unwrap().get())
.await
.unwrap()
.unwrap()
};
message_component
.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.custom_id("DICTIONARY_LIST").content("").embed(|e| {
e.title("辞書一覧");
.create_response(&ctx.http, CreateInteractionResponse::UpdateMessage(
CreateInteractionResponseMessage::new()
.content("")
.embed(CreateEmbed::new()
.title("辞書一覧")
.fields({
let fields = vec![];
for rule in config.dictionary.rules {
e.field(
rule.id,
let field = (
rule.id.clone(),
format!("{} -> {}", rule.rule, rule.to),
true,
);
fields.push(field);
}
e
})
})
})
fields
}))
))
.await
.unwrap();
}
"TTS_CONFIG_SERVER_ADD_DICTIONARY_BUTTON" => {
message_component
.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::Modal)
.interaction_response_data(|d| {
d.custom_id("TTS_CONFIG_SERVER_ADD_DICTIONARY")
.title("辞書追加")
.components(|c| {
c.create_action_row(|a| {
a.create_input_text(|i| {
i.style(InputTextStyle::Short)
.label("Rule name")
.custom_id("rule_name")
.create_response(&ctx.http,
CreateInteractionResponse::Modal(
CreateModal::new("TTS_CONFIG_SERVER_ADD_DICTIONARY", "辞書追加")
.components({
vec![
CreateActionRow::InputText(
CreateInputText::new(
InputTextStyle::Short,
"rule_name",
"辞書名"
)
.required(true)
})
})
.create_action_row(|a| {
a.create_input_text(|i| {
i.style(InputTextStyle::Paragraph)
.label("From")
.custom_id("from")
),
CreateActionRow::InputText(
CreateInputText::new(
InputTextStyle::Paragraph,
"from",
"変換元(正規表現)"
)
.required(true)
})
})
.create_action_row(|a| {
a.create_input_text(|i| {
i.style(InputTextStyle::Short)
.label("To")
.custom_id("to")
),
CreateActionRow::InputText(
CreateInputText::new(
InputTextStyle::Short,
"to",
"変換先"
)
.required(true)
)
]
})
})
})
})
})
))
.await
.unwrap();
}
"SET_AUTOSTART_CHANNEL" => {
let autostart_channel_id = if message_component.data.values.len() == 0 {
let autostart_channel_id = match message_component.data.kind {
ComponentInteractionDataKind::StringSelect { values, .. } => {
if values.len() == 0 {
None
} else {
let ch = message_component.data.values[0]
.strip_prefix("SET_AUTOSTART_CHANNEL_")
.unwrap();
Some(u64::from_str_radix(ch, 10).unwrap())
Some(u64::from_str_radix(&values[0].strip_prefix("SET_AUTOSTART_CHANNEL_").unwrap(), 10).unwrap())
}
}
_ => panic!("Cannot get index"),
};
{
let data_read = ctx.data.read().await;
@ -310,25 +292,19 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
let mut config = database
.get_server_config_or_default(message_component.guild_id.unwrap().0)
.get_server_config_or_default(message_component.guild_id.unwrap().get())
.await
.unwrap()
.unwrap();
config.autostart_channel_id = autostart_channel_id;
database
.set_server_config(message_component.guild_id.unwrap().0, config)
.set_server_config(message_component.guild_id.unwrap().get(), config)
.await
.unwrap();
};
message_component
.create_interaction_response(&ctx.http, |c| {
c.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.content("自動参加チャンネルを設定しました。")
.components(|f| f)
})
})
.create_response(&ctx.http, CreateInteractionResponse::UpdateMessage(CreateInteractionResponseMessage::new().content("自動参加チャンネルを設定しました。")))
.await
.unwrap();
}
@ -341,7 +317,7 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.get_server_config_or_default(message_component.guild_id.unwrap().0)
.get_server_config_or_default(message_component.guild_id.unwrap().get())
.await
.unwrap()
.unwrap()
@ -356,95 +332,73 @@ impl EventHandler for Handler {
.await
.unwrap();
message_component
.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.custom_id("SET_AUTOSTART_FORM")
.content("自動参加チャンネル設定")
.components(|c| {
c.create_action_row(|a| {
a.create_select_menu(|m| {
m.min_values(0)
.max_values(1)
.disabled(false)
.custom_id("SET_AUTOSTART_CHANNEL")
.options(|o| {
// Create channel list
let mut options = Vec::new();
for (id, channel) in channels {
if channel.kind != ChannelType::Voice {
continue;
}
o.create_option(|co| {
co.label(channel.name)
.description(
channel
.topic
.unwrap_or(String::from(
"No topic provided.",
)),
let description = channel.topic.unwrap_or_else(|| String::from("No topic provided."));
let option = CreateSelectMenuOption::new(
&channel.name,
format!("SET_AUTOSTART_CHANNEL_{}", id.get())
)
.value(format!("SET_AUTOSTART_CHANNEL_{}", id.0))
.default_selection(channel.id.0 == autostart_channel_id)
});
.description(description)
.default_selection(channel.id.get() == autostart_channel_id);
options.push(option);
}
o
})
})
})
})
})
})
message_component
.create_response(&ctx.http,
CreateInteractionResponse::UpdateMessage(
CreateInteractionResponseMessage::new()
.content("自動参加チャンネル設定")
.components(vec![
CreateActionRow::SelectMenu(
CreateSelectMenu::new(
"SET_AUTOSTART_CHANNEL",
CreateSelectMenuKind::String { options }
)
.min_values(0)
.max_values(1)
)
])
))
.await
.unwrap();
}
},
"TTS_CONFIG_SERVER" => {
message_component
.create_interaction_response(&ctx.http, |f| {
f.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.content("サーバー設定")
.custom_id("TTS_CONFIG_SERVER")
.components(|c| {
c.create_action_row(|a| {
a.create_button(|b| {
b.custom_id(
"TTS_CONFIG_SERVER_ADD_DICTIONARY_BUTTON",
)
.create_response(&ctx.http,
CreateInteractionResponse::UpdateMessage(
CreateInteractionResponseMessage::new()
.content("サーバー設定")
.components(vec![
CreateActionRow::Buttons(vec![
CreateButton::new("TTS_CONFIG_SERVER_ADD_DICTIONARY_BUTTON")
.label("辞書を追加")
.style(ButtonStyle::Primary)
})
.create_button(|b| {
b.custom_id(
"TTS_CONFIG_SERVER_REMOVE_DICTIONARY_BUTTON",
)
.style(ButtonStyle::Primary),
CreateButton::new("TTS_CONFIG_SERVER_REMOVE_DICTIONARY_BUTTON")
.label("辞書を削除")
.style(ButtonStyle::Danger)
})
.create_button(|b| {
b.custom_id(
"TTS_CONFIG_SERVER_SHOW_DICTIONARY_BUTTON",
)
.style(ButtonStyle::Danger),
CreateButton::new("TTS_CONFIG_SERVER_SHOW_DICTIONARY_BUTTON")
.label("辞書一覧")
.style(ButtonStyle::Primary)
})
.create_button(|b| {
b.custom_id(
"TTS_CONFIG_SERVER_SET_AUTOSTART_CHANNEL"
)
.style(ButtonStyle::Primary),
CreateButton::new("TTS_CONFIG_SERVER_SET_AUTOSTART_CHANNEL")
.label("自動参加チャンネル")
.style(ButtonStyle::Primary)
})
})
})
})
})
])
])
))
.await
.unwrap();
}
_ => {}
}
if let Some(v) = message_component.data.values.get(0) {
match message_component.data.kind {
ComponentInteractionDataKind::StringSelect { values, .. } if !values.is_empty() => {
let res = &values[0];
let data_read = ctx.data.read().await;
let mut config = {
@ -454,16 +408,16 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.get_user_config_or_default(message_component.user.id.0)
.get_user_config_or_default(message_component.user.id.get())
.await
.unwrap()
.unwrap()
};
let res = (*v).clone();
let mut config_changed = false;
let mut voicevox_changed = false;
match &*res {
match res.as_str() {
"TTS_CONFIG_ENGINE_SELECTED_GOOGLE" => {
config.tts_type = Some(TTSType::GCP);
config_changed = true;
@ -474,13 +428,12 @@ impl EventHandler for Handler {
}
_ => {
if res.starts_with("TTS_CONFIG_VOICEVOX_SPEAKER_SELECTED_") {
config.voicevox_speaker = Some(
i64::from_str_radix(
&res.replace("TTS_CONFIG_VOICEVOX_SPEAKER_SELECTED_", ""),
10,
)
.unwrap(),
);
let speaker_id = res
.strip_prefix("TTS_CONFIG_VOICEVOX_SPEAKER_SELECTED_")
.and_then(|id_str| id_str.parse::<i64>().ok())
.expect("Invalid speaker ID format");
config.voicevox_speaker = Some(speaker_id);
config_changed = true;
voicevox_changed = true;
}
@ -494,27 +447,28 @@ impl EventHandler for Handler {
.clone();
let mut database = database.lock().await;
database
.set_user_config(message_component.user.id.0, config.clone())
.set_user_config(message_component.user.id.get(), config.clone())
.await
.unwrap();
if voicevox_changed && config.tts_type.unwrap_or(TTSType::GCP) == TTSType::GCP {
message_component.create_interaction_response(&ctx.http, |f| {
f.interaction_response_data(|d| {
d.content("設定しました\nこの音声を使うにはAPIをGoogleからVOICEVOXに変更する必要があります。")
.flags(MessageFlags::EPHEMERAL)
})
}).await.unwrap();
let response_content = if voicevox_changed && config.tts_type.unwrap_or(TTSType::GCP) == TTSType::GCP {
"設定しました\nこの音声を使うにはAPIをGoogleからVOICEVOXに変更する必要があります。"
} else {
"設定しました"
};
message_component
.create_interaction_response(&ctx.http, |f| {
f.interaction_response_data(|d| {
d.content("設定しました").flags(MessageFlags::EPHEMERAL)
})
})
.create_response(&ctx.http,
CreateInteractionResponse::Message(
CreateInteractionResponseMessage::new()
.content(response_content)
.ephemeral(true)
))
.await
.unwrap();
}
},
_ => {
}
}
}

View File

@ -14,10 +14,7 @@ use data::{DatabaseClientData, TTSClientData, TTSData};
use database::database::Database;
use event_handler::Handler;
use serenity::{
client::Client,
framework::StandardFramework,
futures::lock::Mutex,
prelude::{GatewayIntents, RwLock},
all::{standard::Configuration, ApplicationId}, client::Client, framework::StandardFramework, futures::lock::Mutex, prelude::{GatewayIntents, RwLock}
};
use tts::{gcp_tts::gcp_tts::TTS, voicevox::voicevox::VOICEVOX};
@ -32,11 +29,12 @@ use songbird::SerenityInit;
/// client.start().await;
/// ```
async fn create_client(prefix: &str, token: &str, id: u64) -> Result<Client, serenity::Error> {
let framework = StandardFramework::new().configure(|c| c.with_whitespace(true).prefix(prefix));
let framework = StandardFramework::new();
framework.configure(Configuration::new().with_whitespace(true).prefix(prefix));
Client::builder(token, GatewayIntents::all())
.event_handler(Handler)
.application_id(id)
.application_id(ApplicationId::new(id))
.framework(framework)
.register_songbird()
.await