aboutsummaryrefslogtreecommitdiffstats
path: root/src/commands
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/commands/ai.rs14
-rw-r--r--src/commands/tts.rs59
2 files changed, 22 insertions, 51 deletions
diff --git a/src/commands/ai.rs b/src/commands/ai.rs
index a7a9a7e..61fb471 100644
--- a/src/commands/ai.rs
+++ b/src/commands/ai.rs
@@ -30,18 +30,8 @@ pub async fn senator(
30 }) 30 })
31 .ok_or_else(lang::err_not_in_voice)?; 31 .ok_or_else(lang::err_not_in_voice)?;
32 32
33 let tts_url = format!( 33 let (audio_data, _) =
34 "https://translate.google.com/translate_tts?ie=UTF-8&q={}&tl=pl&client=tw-ob", 34 crate::tts::synthesize(&ctx.data().config, &ctx.data().http_client, &response).await?;
35 crate::commands::tts::urlencoding(&response)
36 );
37 let audio_data = ctx
38 .data()
39 .http_client
40 .get(&tts_url)
41 .send()
42 .await?
43 .bytes()
44 .await?;
45 35
46 let call = ctx 36 let call = ctx
47 .data() 37 .data()
diff --git a/src/commands/tts.rs b/src/commands/tts.rs
index 4a99539..8d20179 100644
--- a/src/commands/tts.rs
+++ b/src/commands/tts.rs
@@ -3,6 +3,7 @@ use poise::serenity_prelude as serenity;
3use crate::Data; 3use crate::Data;
4use crate::error::{Error, Result}; 4use crate::error::{Error, Result};
5use crate::lang; 5use crate::lang;
6use tracing::warn;
6 7
7type Context<'a> = poise::Context<'a, Data, Error>; 8type Context<'a> = poise::Context<'a, Data, Error>;
8 9
@@ -14,7 +15,7 @@ pub enum OutputMode {
14 Vc, 15 Vc,
15} 16}
16 17
17/// Generate Google TTS (Polish) and output to file or voice channel 18/// Generate TTS (Piper locally, Google as fallback) and output to file or voice channel
18#[poise::command(slash_command)] 19#[poise::command(slash_command)]
19pub async fn tts( 20pub async fn tts(
20 ctx: Context<'_>, 21 ctx: Context<'_>,
@@ -22,23 +23,10 @@ pub async fn tts(
22 #[description = "Output destination (file or vc)"] output: Option<OutputMode>, 23 #[description = "Output destination (file or vc)"] output: Option<OutputMode>,
23) -> Result<()> { 24) -> Result<()> {
24 ctx.defer().await?; 25 ctx.defer().await?;
25 let lang = "pl";
26 let tts_url = format!(
27 "https://translate.google.com/translate_tts?ie=UTF-8&q={}&tl={}&client=tw-ob",
28 urlencoding(&text),
29 lang
30 );
31 26
32 let output = output.unwrap_or(OutputMode::Vc); 27 let output = output.unwrap_or(OutputMode::Vc);
33 28 let (audio_data, ext) =
34 let audio_data = ctx 29 crate::tts::synthesize(&ctx.data().config, &ctx.data().http_client, &text).await?;
35 .data()
36 .http_client
37 .get(&tts_url)
38 .send()
39 .await?
40 .bytes()
41 .await?;
42 30
43 match output { 31 match output {
44 OutputMode::File => { 32 OutputMode::File => {
@@ -46,17 +34,22 @@ pub async fn tts(
46 .await 34 .await
47 .ok(); 35 .ok();
48 let path = format!( 36 let path = format!(
49 "{}/tts_{}.mp3", 37 "{}/tts_{}.{}",
50 crate::config::TEMP_PATH, 38 crate::config::TEMP_PATH,
51 uuid::Uuid::new_v4() 39 uuid::Uuid::new_v4(),
40 ext
52 ); 41 );
53 tokio::fs::write(&path, &audio_data).await?; 42 tokio::fs::write(&path, &audio_data).await?;
54 ctx.send( 43 if let Err(e) = ctx
55 poise::CreateReply::default() 44 .send(
56 .content(lang::L_TTS_SAVED) 45 poise::CreateReply::default()
57 .attachment(serenity::CreateAttachment::path(&path).await.unwrap()), 46 .content(lang::L_TTS_SAVED)
58 ) 47 .attachment(serenity::CreateAttachment::path(&path).await.unwrap()),
59 .await?; 48 )
49 .await
50 {
51 warn!("Failed to send /tts file reply: {e}");
52 }
60 } 53 }
61 OutputMode::Vc => { 54 OutputMode::Vc => {
62 let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; 55 let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?;
@@ -81,24 +74,12 @@ pub async fn tts(
81 if call_lock.current_channel().is_some() { 74 if call_lock.current_channel().is_some() {
82 call_lock.play_input(input); 75 call_lock.play_input(input);
83 } 76 }
84 ctx.say(lang::L_TTS_PLAYING).await?; 77 if let Err(e) = ctx.say(lang::L_TTS_PLAYING).await {
85 } 78 warn!("Failed to send /tts voice reply: {e}");
86 }
87 Ok(())
88}
89
90pub fn urlencoding(s: &str) -> String {
91 let mut out = String::with_capacity(s.len());
92 for &byte in s.as_bytes() {
93 match byte {
94 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'_' | b'-' | b'.' | b'~' => {
95 out.push(byte as char)
96 } 79 }
97 b' ' => out.push('+'),
98 _ => out.push_str(&format!("%{:02X}", byte)),
99 } 80 }
100 } 81 }
101 out 82 Ok(())
102} 83}
103 84
104pub fn commands() -> Vec<poise::Command<Data, Error>> { 85pub fn commands() -> Vec<poise::Command<Data, Error>> {