songy

telegram bot as a songbook
git clone git://git.relim.de/songy.git
Log | Files | Refs | README | LICENSE

commit 58577ea45e41c56ea3628dfb47edc1649f4feb12
parent ff3588022872e8851cda6d6c5d746407c830ac1c
Author: devnibo <kroekerrobin@gmail.com>
Date:   Sun, 24 Sep 2023 15:49:00 +0200

Use rustfmt

Diffstat:
Msrc/i18n.rs | 214++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/main.rs | 1030++++++++++++++++++++++++++++++++++++++++---------------------------------------
2 files changed, 629 insertions(+), 615 deletions(-)

diff --git a/src/i18n.rs b/src/i18n.rs @@ -2,138 +2,140 @@ use std::fs; #[derive(Clone)] pub struct ReportMsgs { - pub msg: String, - pub error_msg: String, - pub success_msg: String, - pub cancel_msg: String + pub msg: String, + pub error_msg: String, + pub success_msg: String, + pub cancel_msg: String, } #[derive(Clone)] pub struct I18n { - lang: String, - pub start_msg: String, - pub song_not_found: String, - pub report: ReportMsgs + lang: String, + pub start_msg: String, + pub song_not_found: String, + pub report: ReportMsgs, } impl I18n { - pub fn new(lang: String, songs_path: String) -> Self { - match lang.as_str() { - "de" => { - Self { - lang, - start_msg: String::from(format!( - "Hallo. Dies ist ein digitales Liederbuch. :)\n\ + pub fn new(lang: String, songs_path: String) -> Self { + match lang.as_str() { + "de" => Self { + lang, + start_msg: String::from(format!( + "Hallo. Dies ist ein digitales Liederbuch. :)\n\ Befehle:\n\ /list - Listet alle Lieder auf\n\ {}\ Ansonsten tippe einfach den Titel oder Teile des Titels \ des Liedes ein und du bekommst dein Lied zugeschickt.", - get_commands(songs_path).as_str() - )), - song_not_found: String::from("Kein Lied mit diesem Titel gefunden."), - report: ReportMsgs{ - msg: String::from("Bitte sende einen gefundenen Fehler \ - entweder als Text oder Sprachnachricht."), - error_msg: String::from("Das hat nicht funktioniert. Versuche es nochmal oder /cancel."), - success_msg: String::from("Deine Korrektur wurde erfolgreich gemeldet."), - cancel_msg: String::from("Das Fehlermelden wurde abgebrochen.") - } - } - }, - "md" => { - Self { - lang, - start_msg: String::from(format!( - "Salut! Această e o carte de cântari digitală. :)\n\ + get_commands(songs_path).as_str() + )), + song_not_found: String::from("Kein Lied mit diesem Titel gefunden."), + report: ReportMsgs { + msg: String::from( + "Bitte sende einen gefundenen Fehler \ + entweder als Text oder Sprachnachricht.", + ), + error_msg: String::from( + "Das hat nicht funktioniert. Versuche es nochmal oder /cancel.", + ), + success_msg: String::from("Deine Korrektur wurde erfolgreich gemeldet."), + cancel_msg: String::from("Das Fehlermelden wurde abgebrochen."), + }, + }, + "md" => Self { + lang, + start_msg: String::from(format!( + "Salut! Această e o carte de cântari digitală. :)\n\ Comenzi:\n\ /list - Listează toate cântările\n\ {}\ Deasemenea puteți introduce titlul sau cuvinte din titlul \ cântării iar bot-ul va găsi piesa corespondentă.", - get_commands(songs_path).as_str() - )), - song_not_found: String::from("Niciun cântec găsit cu acest nume"), - report: ReportMsgs{ - msg: String::from("Vă rugăm să trimiteți eroare pe care \ - ați găsit-o fie ca mesaj text sau vocal."), - error_msg: String::from("Asta nu a mers. Încercați din nou sau /cancel"), - success_msg: String::from("A raportat corect corectia."), - cancel_msg: String::from("Raportarea a fost anulată.") - } - } - }, - _ => { - Self { - lang, - start_msg: String::from(format!( - "Hello. This is a digital song book. :)\n\ + get_commands(songs_path).as_str() + )), + song_not_found: String::from("Niciun cântec găsit cu acest nume"), + report: ReportMsgs { + msg: String::from( + "Vă rugăm să trimiteți eroare pe care \ + ați găsit-o fie ca mesaj text sau vocal.", + ), + error_msg: String::from("Asta nu a mers. Încercați din nou sau /cancel"), + success_msg: String::from("A raportat corect corectia."), + cancel_msg: String::from("Raportarea a fost anulată."), + }, + }, + _ => Self { + lang, + start_msg: String::from(format!( + "Hello. This is a digital song book. :)\n\ Commands:\n\ /list - Lists all songs\n\ {}\ Otherwise simply type the title or parts of the title \ of the song and you will receive the song.", - get_commands(songs_path).as_str() - )), - song_not_found: String::from("Didn't find any song with this title."), - report: ReportMsgs{ - msg: String::from("Please send an error you found \ - either as text or voice message."), - error_msg: String::from("That didn't work. Try again or /cancel."), - success_msg: String::from("Successfully reported your correction."), - cancel_msg: String::from("Reporting canceled.") - } - } - } - } - } - pub fn format(&self, name: &String) -> String { - let mut formatted_name = name.to_string(); - match self.lang.as_str() { - "de" => { - formatted_name = formatted_name.replace("Ö", "Oe"); - formatted_name = formatted_name.replace("ö", "oe"); - formatted_name = formatted_name.replace("Ü", "Ue"); - formatted_name = formatted_name.replace("ü", "ue"); - formatted_name = formatted_name.replace("Ä", "Ae"); - formatted_name = formatted_name.replace("ä", "ae"); - formatted_name = formatted_name.replace("ß", "ss"); - }, - "md" => { - formatted_name = formatted_name.replace("ă", "a"); - formatted_name = formatted_name.replace("â", "a"); - formatted_name = formatted_name.replace("î", "i"); - formatted_name = formatted_name.replace("ș", "s"); - formatted_name = formatted_name.replace("ț", "t"); - }, - _ => {} - } - formatted_name = formatted_name.replace("-", "_"); - formatted_name = formatted_name.replace(" ", "_"); - return formatted_name; - } + get_commands(songs_path).as_str() + )), + song_not_found: String::from("Didn't find any song with this title."), + report: ReportMsgs { + msg: String::from( + "Please send an error you found \ + either as text or voice message.", + ), + error_msg: String::from("That didn't work. Try again or /cancel."), + success_msg: String::from("Successfully reported your correction."), + cancel_msg: String::from("Reporting canceled."), + }, + }, + } + } + pub fn format(&self, name: &String) -> String { + let mut formatted_name = name.to_string(); + match self.lang.as_str() { + "de" => { + formatted_name = formatted_name.replace("Ö", "Oe"); + formatted_name = formatted_name.replace("ö", "oe"); + formatted_name = formatted_name.replace("Ü", "Ue"); + formatted_name = formatted_name.replace("ü", "ue"); + formatted_name = formatted_name.replace("Ä", "Ae"); + formatted_name = formatted_name.replace("ä", "ae"); + formatted_name = formatted_name.replace("ß", "ss"); + } + "md" => { + formatted_name = formatted_name.replace("ă", "a"); + formatted_name = formatted_name.replace("â", "a"); + formatted_name = formatted_name.replace("î", "i"); + formatted_name = formatted_name.replace("ș", "s"); + formatted_name = formatted_name.replace("ț", "t"); + } + _ => {} + } + formatted_name = formatted_name.replace("-", "_"); + formatted_name = formatted_name.replace(" ", "_"); + return formatted_name; + } } fn get_commands(songs_path: String) -> String { - let mut commands: String = String::new(); - for name in get_folder_names(&songs_path) { - commands.push_str(&("/".to_owned() + name.as_str() + "\n")); - } - return commands; + let mut commands: String = String::new(); + for name in get_folder_names(&songs_path) { + commands.push_str(&("/".to_owned() + name.as_str() + "\n")); + } + return commands; } pub fn get_folder_names(songs_path: &String) -> Vec<String> { - let songs_dir = fs::read_dir(songs_path).unwrap(); - let mut folder_names: Vec<String> = vec![]; - let mut is_dir: bool; - let mut dir_entry; - for f in songs_dir { - dir_entry = f.expect("Error: f"); - is_dir = dir_entry.file_type().unwrap().is_dir(); - if is_dir { - let name: String = dir_entry.file_name().to_str().unwrap().to_string(); - folder_names.push(name) - } - } - return folder_names; + let songs_dir = fs::read_dir(songs_path).unwrap(); + let mut folder_names: Vec<String> = vec![]; + let mut is_dir: bool; + let mut dir_entry; + for f in songs_dir { + dir_entry = f.expect("Error: f"); + is_dir = dir_entry.file_type().unwrap().is_dir(); + if is_dir { + let name: String = dir_entry.file_name().to_str().unwrap().to_string(); + folder_names.push(name) + } + } + return folder_names; } diff --git a/src/main.rs b/src/main.rs @@ -1,23 +1,23 @@ +use bytes::Bytes; use clap::Parser; -use frankenstein::Api; -use frankenstein::TelegramApi; -use frankenstein::SendMessageParams; -use frankenstein::GetUpdatesParams; -use frankenstein::ChatId; -use frankenstein::Message; use frankenstein::api_params::File; -use frankenstein::api_params::InputFile; use frankenstein::api_params::GetFileParams; +use frankenstein::api_params::InputFile; use frankenstein::api_params::SendDocumentParams; -use frankenstein::objects::UpdateContent; use frankenstein::objects::AllowedUpdate; +use frankenstein::objects::UpdateContent; +use frankenstein::Api; +use frankenstein::ChatId; +use frankenstein::GetUpdatesParams; +use frankenstein::Message; +use frankenstein::SendMessageParams; +use frankenstein::TelegramApi; use std::fs::DirEntry; -use std::{fs, thread, time, process}; use std::io::Write; -use bytes::Bytes; +use std::{fs, process, thread, time}; mod i18n; -use i18n::I18n; use config_file::FromConfigFile; +use i18n::I18n; use serde::Deserialize; /* @@ -31,578 +31,590 @@ const MAX_TEXT_LEN: usize = 4096; #[derive(Parser, Debug, Deserialize)] struct Config { - #[arg(short, long, help = "telegram bot api token")] - token: Option<String>, - #[arg(short, long, help = "path to folder with pdf files")] - songs_path: Option<String>, - #[arg(short, long, default_value = "en", help = "language that the bot speaks: 'en', 'de' or 'md'")] - lang: Option<String>, - #[arg(short = 'f', long, help = "path to search file")] - search_file: Option<String>, - #[arg(short, long, help = "path to folder where reports will be saved")] - reports_path: Option<String>, - #[arg(short, long, help = "path to yml config file")] - config: Option<String> + #[arg(short, long, help = "telegram bot api token")] + token: Option<String>, + #[arg(short, long, help = "path to folder with pdf files")] + songs_path: Option<String>, + #[arg( + short, + long, + default_value = "en", + help = "language that the bot speaks: 'en', 'de' or 'md'" + )] + lang: Option<String>, + #[arg(short = 'f', long, help = "path to search file")] + search_file: Option<String>, + #[arg(short, long, help = "path to folder where reports will be saved")] + reports_path: Option<String>, + #[arg(short, long, help = "path to yml config file")] + config: Option<String>, } impl Config { - pub fn new() -> Self { - Self { - token: None, - songs_path: None, - lang: None, - search_file: None, - reports_path: None, - config: None - } - } + pub fn new() -> Self { + Self { + token: None, + songs_path: None, + lang: None, + search_file: None, + reports_path: None, + config: None, + } + } } struct SongNotFound { - message: String + message: String, } struct HandleArg { - api: Api, - msg: Option<Message>, - token: String, - reports_path: Option<String>, - i18n: I18n, - songs_path: String, - search_file: Option<String> + api: Api, + msg: Option<Message>, + token: String, + reports_path: Option<String>, + i18n: I18n, + songs_path: String, + search_file: Option<String>, } struct HandleResult { - wait_for_report: bool + wait_for_report: bool, } enum OutgoingTextMsg { - DirEntry(Vec<DirEntry>), - String(Vec<String>) + DirEntry(Vec<DirEntry>), + String(Vec<String>), } struct FindSongArgs { - songs_path: String, - i18n: I18n, - search_string: String, - search_type: SearchType, - search_file: String + songs_path: String, + i18n: I18n, + search_string: String, + search_type: SearchType, + search_file: String, } #[derive(Debug)] enum SearchType { - Title, - FullText + Title, + FullText, } struct SearchResult { - ss_in_title: Vec<String>, - ss_in_lyrics: Vec<String> + ss_in_title: Vec<String>, + ss_in_lyrics: Vec<String>, } enum ReportFileType { - Voice(Bytes), - Text(String) + Voice(Bytes), + Text(String), } fn main() { - let config = get_config(); - let api = Api::new(&config.token.clone().unwrap().as_str()); - let is_reports_path = config.reports_path.is_some(); - let songs_path: String = add_ending_slash(config.songs_path.unwrap()); - let mut handle_arg = HandleArg { - api: api.clone(), - msg: None, - token: config.token.unwrap().clone(), - reports_path: config.reports_path.clone(), - i18n: I18n::new(config.lang.unwrap(), songs_path.clone()), - songs_path: songs_path.clone(), - search_file: config.search_file.clone() - }; - let mut updates_params = GetUpdatesParams::builder() - .allowed_updates(vec![AllowedUpdate::Message]) - .build(); - let mut res = HandleResult{ wait_for_report: false }; - let mut handle_res: Option<HandleResult>; - loop { - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - let result = TelegramApi::get_updates(&api, &updates_params); - match result { - Ok(val) => { - for update in &val.result { - updates_params.offset = Some(i64::from(update.update_id) + 1); - match &update.content { - UpdateContent::Message(msg) => { - handle_arg.msg = Some(msg.clone()); - if is_reports_path && res.wait_for_report { - handle_res = handle_report(&handle_arg); - if handle_res.is_some() { - res = handle_res.unwrap(); - } - continue; - } - if msg.text.is_some() { - handle_res = handle_text_message(&handle_arg); - if handle_res.is_some() { - res = handle_res.unwrap(); - } - } - }, - _ => {} - } - } - }, - Err(_err) => { - eprintln!("Error receiving updates from Telegram Bot API."); - } - } - } + let config = get_config(); + let api = Api::new(&config.token.clone().unwrap().as_str()); + let is_reports_path = config.reports_path.is_some(); + let songs_path: String = add_ending_slash(config.songs_path.unwrap()); + let mut handle_arg = HandleArg { + api: api.clone(), + msg: None, + token: config.token.unwrap().clone(), + reports_path: config.reports_path.clone(), + i18n: I18n::new(config.lang.unwrap(), songs_path.clone()), + songs_path: songs_path.clone(), + search_file: config.search_file.clone(), + }; + let mut updates_params = GetUpdatesParams::builder() + .allowed_updates(vec![AllowedUpdate::Message]) + .build(); + let mut res = HandleResult { + wait_for_report: false, + }; + let mut handle_res: Option<HandleResult>; + loop { + let dur = time::Duration::from_millis(500); + thread::sleep(dur); + let result = TelegramApi::get_updates(&api, &updates_params); + match result { + Ok(val) => { + for update in &val.result { + updates_params.offset = Some(i64::from(update.update_id) + 1); + match &update.content { + UpdateContent::Message(msg) => { + handle_arg.msg = Some(msg.clone()); + if is_reports_path && res.wait_for_report { + handle_res = handle_report(&handle_arg); + if handle_res.is_some() { + res = handle_res.unwrap(); + } + continue; + } + if msg.text.is_some() { + handle_res = handle_text_message(&handle_arg); + if handle_res.is_some() { + res = handle_res.unwrap(); + } + } + } + _ => {} + } + } + } + Err(_err) => { + eprintln!("Error receiving updates from Telegram Bot API."); + } + } + } } fn get_config() -> Config { - let mut config: Config = Config::new(); - let args = Config::parse(); - if args.config.is_some() { - config = Config::from_config_file(args.config.unwrap()).unwrap(); - } - if args.token.is_some() { - config.token = args.token; - } - if args.songs_path.is_some() { - config.songs_path = args.songs_path; - } - if args.lang.is_some() { - config.lang = args.lang; - } - if args.search_file.is_some() { - config.search_file = args.search_file; - } - if args.reports_path.is_some() { - config.reports_path = args.reports_path; - } - if config.token.is_none() || config.songs_path.is_none() { - eprintln!("Provide at least a --token and a --songs-path."); - process::exit(-1); - } - config + let mut config: Config = Config::new(); + let args = Config::parse(); + if args.config.is_some() { + config = Config::from_config_file(args.config.unwrap()).unwrap(); + } + if args.token.is_some() { + config.token = args.token; + } + if args.songs_path.is_some() { + config.songs_path = args.songs_path; + } + if args.lang.is_some() { + config.lang = args.lang; + } + if args.search_file.is_some() { + config.search_file = args.search_file; + } + if args.reports_path.is_some() { + config.reports_path = args.reports_path; + } + if config.token.is_none() || config.songs_path.is_none() { + eprintln!("Provide at least a --token and a --songs-path."); + process::exit(-1); + } + config } fn add_ending_slash(path: String) -> String { - if !path.ends_with("/") { - let mut new_path = path.to_owned(); - new_path.push_str("/"); - return new_path; - } - else { - return path; - } + if !path.ends_with("/") { + let mut new_path = path.to_owned(); + new_path.push_str("/"); + return new_path; + } else { + return path; + } } fn handle_text_message(args: &HandleArg) -> Option<HandleResult> { - let mut find_song_args = FindSongArgs { - search_string: String::new(), - songs_path: args.songs_path.clone(), - i18n: args.i18n.clone(), - search_type: SearchType::Title, - search_file: String::new() - }; - if args.search_file.as_ref().is_some() { - let search_file = args.search_file.as_ref().unwrap(); - if fs::File::open(search_file).is_ok() { - find_song_args.search_type = SearchType::FullText; - find_song_args.search_file = search_file.to_string(); - } - } - let msg = args.msg.clone().unwrap(); - let text: &str = msg.text.as_ref().unwrap(); - let chat_id: u64 = msg.from.as_ref().unwrap().id; - let mut params = SendMessageParams::builder() - .chat_id(ChatId::Integer(chat_id.try_into().unwrap())) - .text("") - .build(); - match text { - "/start" => { - params.text = (args.i18n.start_msg).to_string(); - send_message(&args.api, &mut params); - }, - "/list" => { - let songs = get_songs(&args.songs_path, None); - params.text = form_msg(OutgoingTextMsg::DirEntry(songs)); - send_message(&args.api, &mut params); - }, - "/report" => { - params.text = args.i18n.report.msg.clone(); - send_message(&args.api, &mut params); - return Some(HandleResult{ wait_for_report: true }); - }, - _ => { - if text.starts_with("/") { - for name in i18n::get_folder_names(&args.songs_path) { - if text == "/".to_owned() + name.as_str() { - let songs = get_songs(&args.songs_path, Some(&name)); - params.text = form_msg(OutgoingTextMsg::DirEntry(songs)); - send_message(&args.api, &mut params); - return None; - } - } - let len = text.as_bytes().len(); - find_song_args.search_string = text[1..len].to_string(); - match title_search(&find_song_args) { - Ok(files) => { - let file = files.get(0); - let input_file = InputFile::builder() - .path(file.unwrap().path()) - .build(); - let send_document_params = SendDocumentParams::builder() - .chat_id(ChatId::Integer(chat_id.try_into().unwrap())) - .document(File::InputFile(input_file)) - .build(); - send_document(&args.api, &send_document_params); - }, - Err(err) => { - eprintln!("{}", err.message); - params.text = (args.i18n.song_not_found).to_string(); - send_message(&args.api, &mut params); - } - } - } - else { - find_song_args.search_string = text.to_string(); - match find_song_args.search_type { - SearchType::Title => { - match title_search(&find_song_args) { - Ok(files) => { - params.text = form_msg(OutgoingTextMsg::DirEntry(files)); - send_message(&args.api, &mut params); - }, - Err(err) => { - eprintln!("{}", err.message); - params.text = (args.i18n.song_not_found).to_string(); - send_message(&args.api, &mut params); - } - } - }, - SearchType::FullText => { - match full_text_search(&find_song_args) { - Ok(search_result) => { - let ss_in_title = form_msg(OutgoingTextMsg::String(search_result.ss_in_title)); - let ss_in_lyrics = form_msg(OutgoingTextMsg::String(search_result.ss_in_lyrics)); - params.text.push_str(&ss_in_title); - params.text.push_str(&ss_in_lyrics); - send_message(&args.api, &mut params); - }, - Err(err) => { - eprintln!("{}", err.message); - params.text = (args.i18n.song_not_found).to_string(); - send_message(&args.api, &mut params); - } - } - } - } - } - } - } - return None; + let mut find_song_args = FindSongArgs { + search_string: String::new(), + songs_path: args.songs_path.clone(), + i18n: args.i18n.clone(), + search_type: SearchType::Title, + search_file: String::new(), + }; + if args.search_file.as_ref().is_some() { + let search_file = args.search_file.as_ref().unwrap(); + if fs::File::open(search_file).is_ok() { + find_song_args.search_type = SearchType::FullText; + find_song_args.search_file = search_file.to_string(); + } + } + let msg = args.msg.clone().unwrap(); + let text: &str = msg.text.as_ref().unwrap(); + let chat_id: u64 = msg.from.as_ref().unwrap().id; + let mut params = SendMessageParams::builder() + .chat_id(ChatId::Integer(chat_id.try_into().unwrap())) + .text("") + .build(); + match text { + "/start" => { + params.text = (args.i18n.start_msg).to_string(); + send_message(&args.api, &mut params); + } + "/list" => { + let songs = get_songs(&args.songs_path, None); + params.text = form_msg(OutgoingTextMsg::DirEntry(songs)); + send_message(&args.api, &mut params); + } + "/report" => { + params.text = args.i18n.report.msg.clone(); + send_message(&args.api, &mut params); + return Some(HandleResult { + wait_for_report: true, + }); + } + _ => { + if text.starts_with("/") { + for name in i18n::get_folder_names(&args.songs_path) { + if text == "/".to_owned() + name.as_str() { + let songs = get_songs(&args.songs_path, Some(&name)); + params.text = form_msg(OutgoingTextMsg::DirEntry(songs)); + send_message(&args.api, &mut params); + return None; + } + } + let len = text.as_bytes().len(); + find_song_args.search_string = text[1..len].to_string(); + match title_search(&find_song_args) { + Ok(files) => { + let file = files.get(0); + let input_file = InputFile::builder().path(file.unwrap().path()).build(); + let send_document_params = SendDocumentParams::builder() + .chat_id(ChatId::Integer(chat_id.try_into().unwrap())) + .document(File::InputFile(input_file)) + .build(); + send_document(&args.api, &send_document_params); + } + Err(err) => { + eprintln!("{}", err.message); + params.text = (args.i18n.song_not_found).to_string(); + send_message(&args.api, &mut params); + } + } + } else { + find_song_args.search_string = text.to_string(); + match find_song_args.search_type { + SearchType::Title => match title_search(&find_song_args) { + Ok(files) => { + params.text = form_msg(OutgoingTextMsg::DirEntry(files)); + send_message(&args.api, &mut params); + } + Err(err) => { + eprintln!("{}", err.message); + params.text = (args.i18n.song_not_found).to_string(); + send_message(&args.api, &mut params); + } + }, + SearchType::FullText => match full_text_search(&find_song_args) { + Ok(search_result) => { + let ss_in_title = + form_msg(OutgoingTextMsg::String(search_result.ss_in_title)); + let ss_in_lyrics = + form_msg(OutgoingTextMsg::String(search_result.ss_in_lyrics)); + params.text.push_str(&ss_in_title); + params.text.push_str(&ss_in_lyrics); + send_message(&args.api, &mut params); + } + Err(err) => { + eprintln!("{}", err.message); + params.text = (args.i18n.song_not_found).to_string(); + send_message(&args.api, &mut params); + } + }, + } + } + } + } + return None; } fn handle_report(args: &HandleArg) -> Option<HandleResult> { - let msg = args.msg.clone().unwrap(); - let reports_path = args.reports_path.clone().unwrap(); - let chat_id: u64 = msg.from.as_ref().unwrap().id; - let mut params = SendMessageParams::builder() - .chat_id(ChatId::Integer(chat_id.try_into().unwrap())) - .text("") - .build(); - if msg.voice.is_some() { - let voice = msg.voice.clone().unwrap(); - match args.api.get_file(&GetFileParams{ file_id: voice.file_id }) { - Ok(file) => { - let file_path = file.result.file_path.unwrap(); - match download_file(&args.token, &file_path) { - Ok(bytes) => save_file(ReportFileType::Voice(bytes), &reports_path), - Err(_) => {} - } - }, - Err(_) => {} - } - params.text = args.i18n.report.success_msg.clone(); - send_message(&args.api, &mut params); - return Some(HandleResult{ wait_for_report: false }); - } - else if msg.text.is_some() { - let text = msg.text.clone().unwrap(); - if text == String::from("/cancel") { - params.text = String::from(args.i18n.report.cancel_msg.clone()); - send_message(&args.api, &mut params); - return Some(HandleResult{ wait_for_report: false }); - } - params.text = args.i18n.report.success_msg.clone(); - send_message(&args.api, &mut params); - save_file(ReportFileType::Text(text), &reports_path); - return Some(HandleResult{ wait_for_report: false }); - } - else { - params.text = args.i18n.report.error_msg.clone(); - send_message(&args.api, &mut params); - return Some(HandleResult{ wait_for_report: true }); - } + let msg = args.msg.clone().unwrap(); + let reports_path = args.reports_path.clone().unwrap(); + let chat_id: u64 = msg.from.as_ref().unwrap().id; + let mut params = SendMessageParams::builder() + .chat_id(ChatId::Integer(chat_id.try_into().unwrap())) + .text("") + .build(); + if msg.voice.is_some() { + let voice = msg.voice.clone().unwrap(); + match args.api.get_file(&GetFileParams { + file_id: voice.file_id, + }) { + Ok(file) => { + let file_path = file.result.file_path.unwrap(); + match download_file(&args.token, &file_path) { + Ok(bytes) => save_file(ReportFileType::Voice(bytes), &reports_path), + Err(_) => {} + } + } + Err(_) => {} + } + params.text = args.i18n.report.success_msg.clone(); + send_message(&args.api, &mut params); + return Some(HandleResult { + wait_for_report: false, + }); + } else if msg.text.is_some() { + let text = msg.text.clone().unwrap(); + if text == String::from("/cancel") { + params.text = String::from(args.i18n.report.cancel_msg.clone()); + send_message(&args.api, &mut params); + return Some(HandleResult { + wait_for_report: false, + }); + } + params.text = args.i18n.report.success_msg.clone(); + send_message(&args.api, &mut params); + save_file(ReportFileType::Text(text), &reports_path); + return Some(HandleResult { + wait_for_report: false, + }); + } else { + params.text = args.i18n.report.error_msg.clone(); + send_message(&args.api, &mut params); + return Some(HandleResult { + wait_for_report: true, + }); + } } fn download_file(token: &String, file_path: &String) -> Result<Bytes, reqwest::Error> { - let url = format!("https://api.telegram.org/file/bot{token}/{file_path}"); - let bytes = reqwest::blocking::get(url)?.bytes()?; - return Ok(bytes); + let url = format!("https://api.telegram.org/file/bot{token}/{file_path}"); + let bytes = reqwest::blocking::get(url)?.bytes()?; + return Ok(bytes); } fn save_file(t: ReportFileType, reports_path: &String) { - let timestamp = chrono::offset::Utc::now().timestamp_millis(); - let filepath = reports_path.to_owned() + "/" + &timestamp.to_string(); - match t { - ReportFileType::Voice(bytes) => { - match fs::File::create(filepath + ".ogg") { - Ok(mut file) => { - let _res = file.write(&bytes); - }, - Err(_) => {} - } - }, - ReportFileType::Text(mut text) => { - match fs::File::create(filepath + ".txt") { - Ok(mut file) => { - text = text + "\n"; - let _res = file.write(text.as_bytes()); - }, - Err(_) => {} - } - } - } + let timestamp = chrono::offset::Utc::now().timestamp_millis(); + let filepath = reports_path.to_owned() + "/" + &timestamp.to_string(); + match t { + ReportFileType::Voice(bytes) => match fs::File::create(filepath + ".ogg") { + Ok(mut file) => { + let _res = file.write(&bytes); + } + Err(_) => {} + }, + ReportFileType::Text(mut text) => match fs::File::create(filepath + ".txt") { + Ok(mut file) => { + text = text + "\n"; + let _res = file.write(text.as_bytes()); + } + Err(_) => {} + }, + } } fn send_document(api: &Api, params: &SendDocumentParams) { - let result = api.send_document(params); - match result { - Err(err) => { - eprintln!("send_document failed."); - dbg!(err); - }, - Ok(_res) => {} - } + let result = api.send_document(params); + match result { + Err(err) => { + eprintln!("send_document failed."); + dbg!(err); + } + Ok(_res) => {} + } } fn send_message(api: &Api, params: &mut SendMessageParams) { - let text_len = params.text.chars().count(); - let msg_count = text_len as f64 / MAX_TEXT_LEN as f64; - if msg_count <= 1.0 { - let result = api.send_message(params); - match result { - Err(err) => { - eprintln!("send_message failed."); - dbg!(err); - }, - Ok(_res) => {} - } - } else { - let mut text: String = params.text.clone(); - let mut part: &str; - loop { - if text.chars().count() > MAX_TEXT_LEN { - match find_last_line_break(text.clone()) { - Ok(index) => { - part = &text[..index]; - params.text = part.to_string(); - let result = api.send_message(params); - match result { - Err(err) => { - eprintln!("send_message failed."); - dbg!(err); - }, - Ok(_res) => {} - } - text = text[index+1..].to_string(); - }, - Err(_) => { - eprintln!("Dude, there's no line break. Deal with it."); - } - } - } else { - params.text = text; - let result = api.send_message(params); - match result { - Err(err) => { - eprintln!("send_message failed."); - dbg!(err); - }, - Ok(_res) => {} - } - break; - } - } - } + let text_len = params.text.chars().count(); + let msg_count = text_len as f64 / MAX_TEXT_LEN as f64; + if msg_count <= 1.0 { + let result = api.send_message(params); + match result { + Err(err) => { + eprintln!("send_message failed."); + dbg!(err); + } + Ok(_res) => {} + } + } else { + let mut text: String = params.text.clone(); + let mut part: &str; + loop { + if text.chars().count() > MAX_TEXT_LEN { + match find_last_line_break(text.clone()) { + Ok(index) => { + part = &text[..index]; + params.text = part.to_string(); + let result = api.send_message(params); + match result { + Err(err) => { + eprintln!("send_message failed."); + dbg!(err); + } + Ok(_res) => {} + } + text = text[index + 1..].to_string(); + } + Err(_) => { + eprintln!("Dude, there's no line break. Deal with it."); + } + } + } else { + params.text = text; + let result = api.send_message(params); + match result { + Err(err) => { + eprintln!("send_message failed."); + dbg!(err); + } + Ok(_res) => {} + } + break; + } + } + } } fn find_last_line_break(text: String) -> Result<usize, usize> { - let mut i: usize = MAX_TEXT_LEN as usize; - loop { - if i == 0 { - return Err(i); - } - match text.chars().nth(i) { - Some(c) => { - if c == '\n' { - return Ok(i); - } - }, - None => { - eprintln!("nth error"); - } - } - i -= 1; - } + let mut i: usize = MAX_TEXT_LEN as usize; + loop { + if i == 0 { + return Err(i); + } + match text.chars().nth(i) { + Some(c) => { + if c == '\n' { + return Ok(i); + } + } + None => { + eprintln!("nth error"); + } + } + i -= 1; + } } fn form_msg(songs: OutgoingTextMsg) -> String { - let mut message = String::new(); - match songs { - OutgoingTextMsg::DirEntry(songs) => { - for song in songs { - let file_name = song.file_name(); - let filename = file_name.to_str().unwrap(); - let s: Vec<&str> = filename.split(".").collect(); - let name = s.get(0).unwrap(); - let mut command: String = "/".to_string(); - command.push_str(name); - command.push_str("\n"); - message.push_str(command.as_str()); - } - }, - OutgoingTextMsg::String(songs) => { - for song in songs { - let mut command = String::from("/"); - command.push_str(&song); - command.push_str("\n"); - message.push_str(command.as_str()); - } - } - } - return message; + let mut message = String::new(); + match songs { + OutgoingTextMsg::DirEntry(songs) => { + for song in songs { + let file_name = song.file_name(); + let filename = file_name.to_str().unwrap(); + let s: Vec<&str> = filename.split(".").collect(); + let name = s.get(0).unwrap(); + let mut command: String = "/".to_string(); + command.push_str(name); + command.push_str("\n"); + message.push_str(command.as_str()); + } + } + OutgoingTextMsg::String(songs) => { + for song in songs { + let mut command = String::from("/"); + command.push_str(&song); + command.push_str("\n"); + message.push_str(command.as_str()); + } + } + } + return message; } fn title_search(args: &FindSongArgs) -> Result<Vec<DirEntry>, SongNotFound> { - let mut result: Vec<DirEntry> = vec![]; - let mut filename: String; - let ss = args.i18n.format(&args.search_string).to_lowercase(); - for file in get_songs(&args.songs_path, None) { - filename = file.file_name().to_str().unwrap().to_string(); - let f: Vec<&str> = filename.split(".").collect(); - let mut name: String = f.get(0).unwrap().to_string(); - name = name.to_lowercase(); - if name.starts_with(&ss) { - // move found song to the beginning - let mut one = vec![file]; - one.append(&mut result); - result = one; - } else if name.contains(&ss) { - result.push(file); - } - } - if result.len() > 0 { - return Ok(result); - } else { - return Err(SongNotFound { message: String::from("Didn't find any song.") }); - } + let mut result: Vec<DirEntry> = vec![]; + let mut filename: String; + let ss = args.i18n.format(&args.search_string).to_lowercase(); + for file in get_songs(&args.songs_path, None) { + filename = file.file_name().to_str().unwrap().to_string(); + let f: Vec<&str> = filename.split(".").collect(); + let mut name: String = f.get(0).unwrap().to_string(); + name = name.to_lowercase(); + if name.starts_with(&ss) { + // move found song to the beginning + let mut one = vec![file]; + one.append(&mut result); + result = one; + } else if name.contains(&ss) { + result.push(file); + } + } + if result.len() > 0 { + return Ok(result); + } else { + return Err(SongNotFound { + message: String::from("Didn't find any song."), + }); + } } fn full_text_search(args: &FindSongArgs) -> Result<SearchResult, SongNotFound> { - let mut ss_in_title: Vec<String> = vec![]; - let mut ss_in_lyrics: Vec<String> = vec![]; - let ss = prepare_for_fulltext_search(&args.search_string); - let content = fs::read_to_string(&args.search_file).unwrap(); - for line in content.lines() { - let s_line: Vec<&str> = line.split(':').collect(); - let name = s_line.get(0).unwrap(); - let song_title = s_line.get(1).unwrap(); - let song_lyrics = s_line.get(2).unwrap(); - if song_title.starts_with(&ss) { - // move found song to the beginning - let mut temp = vec![name.to_string()]; - temp.append(&mut ss_in_title); - ss_in_title = temp; - } - else if song_title.contains(&ss) { - ss_in_title.push(name.to_string()); - } - else if song_lyrics.contains(&ss) { - ss_in_lyrics.push(name.to_string()); - } - } - if ss_in_title.len() == 0 && ss_in_lyrics.len() == 0 { - return Err(SongNotFound { message: String::from("Didn't find any song.") }); - } else { - return Ok(SearchResult { ss_in_title, ss_in_lyrics }); - } + let mut ss_in_title: Vec<String> = vec![]; + let mut ss_in_lyrics: Vec<String> = vec![]; + let ss = prepare_for_fulltext_search(&args.search_string); + let content = fs::read_to_string(&args.search_file).unwrap(); + for line in content.lines() { + let s_line: Vec<&str> = line.split(':').collect(); + let name = s_line.get(0).unwrap(); + let song_title = s_line.get(1).unwrap(); + let song_lyrics = s_line.get(2).unwrap(); + if song_title.starts_with(&ss) { + // move found song to the beginning + let mut temp = vec![name.to_string()]; + temp.append(&mut ss_in_title); + ss_in_title = temp; + } else if song_title.contains(&ss) { + ss_in_title.push(name.to_string()); + } else if song_lyrics.contains(&ss) { + ss_in_lyrics.push(name.to_string()); + } + } + if ss_in_title.len() == 0 && ss_in_lyrics.len() == 0 { + return Err(SongNotFound { + message: String::from("Didn't find any song."), + }); + } else { + return Ok(SearchResult { + ss_in_title, + ss_in_lyrics, + }); + } } fn prepare_for_fulltext_search(string: &String) -> String { - let mut res = String::new(); - // let mut is_last_line_break = false; - for c in string.chars() { - if c.is_alphabetic() { - res.push(c); - // is_last_line_break = false; - } - /* if c == '\n' || c == ' ' { - if !is_last_line_break { - res.push(' '); - is_last_line_break = true; - } - } */ - } - res = res.to_lowercase(); - return res; + let mut res = String::new(); + // let mut is_last_line_break = false; + for c in string.chars() { + if c.is_alphabetic() { + res.push(c); + // is_last_line_break = false; + } + /* if c == '\n' || c == ' ' { + if !is_last_line_break { + res.push(' '); + is_last_line_break = true; + } + } */ + } + res = res.to_lowercase(); + return res; } fn get_songs(songs_path: &String, folder_name: Option<&String>) -> Vec<DirEntry> { - match folder_name { - Some(name) => { - return get_files_recursive(&(songs_path.to_owned() + name)); - }, - None => { - return get_files_recursive(songs_path); - } - } + match folder_name { + Some(name) => { + return get_files_recursive(&(songs_path.to_owned() + name)); + } + None => { + return get_files_recursive(songs_path); + } + } } fn get_files_recursive(folder_path: &String) -> Vec<DirEntry> { - let path = fs::read_dir(folder_path); - let mut is_dir: bool; - let mut songs: Vec<DirEntry> = vec![]; - match path { - Ok(read_dir) => { - for r in read_dir { - match r { - Ok(dir_entry) => { - is_dir = dir_entry.file_type().unwrap().is_dir(); - if is_dir { - let path = dir_entry.path().to_str().unwrap().to_string(); - for song in get_files_recursive(&path) { - songs.push(song); - } - } else { - songs.push(dir_entry); - } - }, - Err(err) => { - eprintln!("Cannot access filepath."); - dbg!(err); - } - } - } - }, - Err(_) => { - eprintln!("Cannot open/read or what ever the path {}.", folder_path); - } - } - songs.sort_by_key(|name| name.file_name().into_string().unwrap().to_lowercase()); - return songs; + let path = fs::read_dir(folder_path); + let mut is_dir: bool; + let mut songs: Vec<DirEntry> = vec![]; + match path { + Ok(read_dir) => { + for r in read_dir { + match r { + Ok(dir_entry) => { + is_dir = dir_entry.file_type().unwrap().is_dir(); + if is_dir { + let path = dir_entry.path().to_str().unwrap().to_string(); + for song in get_files_recursive(&path) { + songs.push(song); + } + } else { + songs.push(dir_entry); + } + } + Err(err) => { + eprintln!("Cannot access filepath."); + dbg!(err); + } + } + } + } + Err(_) => { + eprintln!("Cannot open/read or what ever the path {}.", folder_path); + } + } + songs.sort_by_key(|name| name.file_name().into_string().unwrap().to_lowercase()); + return songs; }