Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,724 changes: 2,107 additions & 617 deletions Cargo.lock

Large diffs are not rendered by default.

25 changes: 13 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ readme = "README.md"
keywords = ["telegram", "telegram-bot", "meme", "quote"]
license = "MIT"
repository = "https://github.com/MihailPreis/WhyDoYou-bot/"
edition = "2021"
edition = "2024"
build = "build.rs"

[package.metadata.docs.rs]
Expand All @@ -32,25 +32,26 @@ tg = ["teloxide"]
db = ["sqlx"]

[dependencies]
teloxide = { version = "0.11.2", features = ["auto-send", "rustls", "ctrlc_handler"], optional = true, default-features = false }
tokio = { version = "1.4", features = ["macros", "rt-multi-thread"] }
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"], optional = true}
teloxide = { version = "0.17", features = ["rustls", "ctrlc_handler"], optional = true, default-features = false }
tokio = { version = "1.47", features = ["macros", "rt-multi-thread"] }
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"], optional = true }
dotenv = "0.15"
log = "0.4"
fern = "0.6.1"
clap = { version = "4.0.26", features = ["color", "derive"] }
fern = "0.7.1"
clap = { version = "4.5", features = ["color", "derive"] }
chrono = "0.4"
regex = "1.4"
lazy_static = "1.4"
imageproc = {version = "0.23.0", features=["default"] }
lazy_static = "1.5"
imageproc = { version = "0.25", features = ["default"] }
rusttype = "0.9"
image = "0.24.2"
reqwest = { version = "0.11", features = ["multipart", "rustls-tls"], default-features=false }
image = "0.25.6"
reqwest = { version = "0.12.23", features = ["multipart", "rustls-tls"], default-features = false }
cfg-if = "1.0.0"
rand = "0.8"
rand = "0.9.2"
uuid = { version = "1.1.1", features = ["v4"] }
mime = "0.3.16"
include_dir = "0.7.2"
ab_glyph = "0.2.31"

[build-dependencies]
chrono = "0.4"
Expand All @@ -59,4 +60,4 @@ chrono = "0.4"
opt-level = 3
lto = true
debug = 0
strip="symbols"
strip = "symbols"
61 changes: 29 additions & 32 deletions src/bots/tg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ use regex::Regex;
use teloxide::net::Download;
use teloxide::prelude::*;
use teloxide::requests::Requester;
use teloxide::types::{
InputFile, MediaAudio, MediaDocument, MediaKind, MediaText, MessageCommon, MessageKind,
UserProfilePhotos,
};
use teloxide::types::{FileId, InputFile, MediaAudio, MediaDocument, MediaKind, MediaText, MessageCommon, MessageKind, UserProfilePhotos};
use teloxide::Bot;

use teloxide::sugar::request::RequestReplyExt;
use crate::engine::engine::build_message;
use crate::models::content_model::ContentModel;
use crate::models::db_conn::DBConn;
Expand Down Expand Up @@ -64,7 +61,7 @@ async fn handler<'a>(bot: Bot, message: Message) -> ResponseResult<()> {
};
}

async fn download_file(bot: &Bot, file_id: String) -> Option<Vec<u8>> {
async fn download_file(bot: &Bot, file_id: FileId) -> Option<Vec<u8>> {
if let Ok(file) = bot.get_file(file_id).await {
let mut out: Vec<u8> = Vec::new();
let mut cursor = Cursor::new(&mut out);
Expand Down Expand Up @@ -133,17 +130,17 @@ async fn handle_message<'a>(bot: &Bot, message: &Message) -> Result<(), HandlerE
match message.text() {
Some(HELP_CMD) => {
bot.send_message(message.chat.id, help_text)
.reply_to_message_id(message.id)
.reply_to(message.id)
.await?;
}
Some(START_CMD) => {
bot.send_message(message.chat.id, help_text)
.reply_to_message_id(message.id)
.reply_to(message.id)
.await?;
}
Some(VERSION_CMD) => {
bot.send_message(message.chat.id, VERSION_STRING)
.reply_to_message_id(message.id)
.reply_to(message.id)
.await?;
}
_ => {}
Expand Down Expand Up @@ -172,7 +169,7 @@ async fn handle_message<'a>(bot: &Bot, message: &Message) -> Result<(), HandlerE
);
return if data == VERSION_CMD {
bot.send_message(message.chat.id, VERSION_STRING)
.reply_to_message_id(message.id)
.reply_to(message.id)
.await?;
Ok(())
} else {
Expand Down Expand Up @@ -244,13 +241,13 @@ async fn handle_message<'a>(bot: &Bot, message: &Message) -> Result<(), HandlerE
Ok(v_data) => match v_data {
Video(video) => {
bot.send_video(message.chat.id, InputFile::memory(video))
.reply_to_message_id(message.id)
.reply_to(message.id)
.await?;
Ok(())
}
Image(image) => {
bot.send_photo(message.chat.id, InputFile::memory(image))
.reply_to_message_id(message.id)
.reply_to(message.id)
.await?;
Ok(())
}
Expand Down Expand Up @@ -294,7 +291,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>

async fn get_help(bot: &Bot, msg: &Message) -> Result<(), HandlerError> {
bot.send_message(msg.chat.id, TEXTS.get_tg("group_help_with_db", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
Ok(())
}
Expand All @@ -303,11 +300,11 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
let resp = DBConn::new().await?.get_words(msg.chat.id.0).await?;
if resp.is_empty() {
bot.send_message(msg.chat.id, TEXTS.get_tg("empty_list_message", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
} else {
bot.send_message(msg.chat.id, resp)
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
}
Ok(())
Expand All @@ -324,7 +321,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
.await?;
if items.is_empty() {
bot.send_message(msg.chat.id, TEXTS.get_tg("empty_list_message", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
} else {
let resp = items
Expand All @@ -333,7 +330,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
.collect::<Vec<String>>()
.join("\n");
bot.send_message(msg.chat.id, resp)
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
}
Ok(())
Expand All @@ -347,7 +344,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
) -> Result<(), HandlerError> {
if match_cmd.len() <= 2 {
bot.send_message(msg.chat.id, TEXTS.get_tg("invalid_arguments", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Args invalid"));
}
Expand All @@ -364,12 +361,12 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
{
Ok(_) => {
bot.send_message(msg.chat.id, TEXTS.get_tg("rm_content_success", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
}
Err(_) => {
bot.send_message(msg.chat.id, TEXTS.get_tg("rm_content_error", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
}
}
Expand All @@ -392,19 +389,19 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
))
.await?;
bot.send_message(msg.chat.id, TEXTS.get_tg("audio_add_success", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Ok(());
}
bot.send_message(msg.chat.id, TEXTS.get_tg("audio_add_dw_error", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Invalid file load"));
}
}
}
bot.send_message(msg.chat.id, TEXTS.get_tg("audio_add_format_error", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Invalid document"));
}
Expand All @@ -426,24 +423,24 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
))
.await?;
bot.send_message(msg.chat.id, TEXTS.get_tg("image_add_success", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Ok(());
}
bot.send_message(msg.chat.id, TEXTS.get_tg("image_add_dw_error", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Invalid file load"));
}
}
bot.send_message(msg.chat.id, TEXTS.get_tg("image_add_format_invalid", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Invalid image format"));
}
}
bot.send_message(msg.chat.id, TEXTS.get_tg("image_add_format_error", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Invalid document"));
}
Expand All @@ -456,7 +453,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
) -> Result<(), HandlerError> {
if match_cmd.len() <= 2 {
bot.send_message(msg.chat.id, TEXTS.get_tg("invalid_arguments", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
// TODO: wtf is this? why it is error?
return Err(HandlerError::from_str("Args invalid"));
Expand All @@ -469,7 +466,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
.trim();
if !WORDS_REGEX.is_match(args) {
bot.send_message(msg.chat.id, TEXTS.get_tg("keyword_error", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Invalid keywoeds"));
}
Expand All @@ -487,7 +484,7 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
) -> Result<(), HandlerError> {
if match_cmd.len() <= 2 {
bot.send_message(msg.chat.id, TEXTS.get_tg("invalid_arguments", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Err(HandlerError::from_str("Args invalid"));
}
Expand Down Expand Up @@ -518,12 +515,12 @@ async fn exec_command(bot: &Bot, message: &Message) -> Result<(), HandlerError>
)
.await?;
bot.send_message(msg.chat.id, TEXTS.get_tg("done_msg", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
return Ok(());
}
bot.send_message(msg.chat.id, TEXTS.get_tg("error_msg", msg))
.reply_to_message_id(msg.id)
.reply_to(msg.id)
.await?;
Err(HandlerError::from_str("Args invalid"))
}
Expand Down
4 changes: 2 additions & 2 deletions src/engine/default_images.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use lazy_static::lazy_static;
use rand::seq::SliceRandom;
use rand::prelude::IndexedRandom;

lazy_static! {
static ref PICS: Vec<&'static [u8]> = vec![
Expand All @@ -10,5 +10,5 @@ lazy_static! {
}

pub fn get_rand_image() -> Vec<u8> {
PICS.choose(&mut rand::thread_rng()).unwrap().to_vec()
PICS.choose(&mut rand::rng()).unwrap().to_vec()
}
23 changes: 11 additions & 12 deletions src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ use std::io::{BufWriter, Cursor};
use std::str;
use std::time::Duration;

use image::{ColorType, EncodableLayout, GenericImageView, ImageFormat, Rgb, RgbImage};
use imageproc::definitions::HasWhite;
use imageproc::drawing::{draw_text, Canvas};
use image::{ColorType, EncodableLayout, ExtendedColorType, GenericImageView, ImageEncoder, ImageFormat, Rgb, RgbImage};
use imageproc::drawing::{draw_text, draw_text_mut, Canvas};
use lazy_static::lazy_static;
use log::{debug, error, info};
use regex::Regex;
use reqwest::{multipart, Client};
use rusttype::{Font, Scale};

use crate::engine::default_images::get_rand_image;
use crate::engine::engine::VData::{Image, Video};
Expand All @@ -28,6 +26,7 @@ use crate::utils::string_utils::{batch, contains_in};
use image::codecs::png::PngEncoder;
use image::imageops::FilterType;
use std::future::Future;
use ab_glyph::{PxScale, Font, FontVec, InvalidFont};

const WORDS_KEY: &str = "WORDS";
const CONVERTER_URL_KEY: &str = "CONVERTER_URL";
Expand All @@ -52,7 +51,7 @@ lazy_static! {
.map(|i| i.to_string())
.collect::<Vec<String>>();
static ref CLIENT: Client = reqwest::Client::new();
static ref FONT_SIZE: Scale = Scale::uniform(64.0);
static ref FONT_SIZE: PxScale = PxScale::from(64.0);
}

/// Create meme-quote if needs with optional image and audio
Expand Down Expand Up @@ -114,19 +113,19 @@ pub async fn build_message(
}

async fn create_image(message: &str, input: Vec<u8>) -> Result<Vec<u8>, HandlerError> {
let font = match Font::try_from_vec(Vec::from(FONT_BYTES)) {
None => {
let font = match FontVec::try_from_vec(Vec::from(FONT_BYTES)) {
Ok(data) => data,
Err(_) => {
return Err(HandlerError::new(String::from("Can not instantiate font")));
}
Some(data) => data,
};
let reader = Cursor::new(input);
let start_image = image::load(reader, ImageFormat::Jpeg)?
.as_rgb8()
.unwrap()
.clone();
let mut out: Vec<u8> = Vec::new();
let (_, _, start_image_w, start_image_h) = start_image.bounds();
let (start_image_w, start_image_h) = start_image.dimensions();
let (new_w, new_h) = aspect_resize(start_image_w, start_image_h, PHOTO_W, PHOTO_H);
let res = image::imageops::resize(&start_image, new_w, new_h, FilterType::Gaussian);
let cursor = BufWriter::new(&mut out);
Expand Down Expand Up @@ -169,7 +168,7 @@ async fn create_image(message: &str, input: Vec<u8>) -> Result<Vec<u8>, HandlerE
let rect = rect_list.get(ind).unwrap();
image = draw_text(
&mut image,
Rgb::white(),
Rgb([255u8, 255u8, 255u8]),
i32::try_from((IMAGE_SIZE - rect.w) / 2)?,
i32::try_from(y)?,
*FONT_SIZE,
Expand All @@ -179,7 +178,7 @@ async fn create_image(message: &str, input: Vec<u8>) -> Result<Vec<u8>, HandlerE
y += FONT_H + 10;
}

let (_, _, img_x_stride, img_y_stride) = res.bounds();
let (img_x_stride, img_y_stride) = res.dimensions();
let x_offset = (IMAGE_SIZE - img_x_stride) / 2;
let y_offset: u32;
if img_y_stride < PHOTO_H {
Expand All @@ -190,7 +189,7 @@ async fn create_image(message: &str, input: Vec<u8>) -> Result<Vec<u8>, HandlerE
res.enumerate_pixels().into_iter().for_each(|px| {
image.draw_pixel(px.0 + x_offset, px.1 + y_offset, px.2.clone());
});
PngEncoder::new(cursor).encode(image.as_bytes(), IMAGE_SIZE, IMAGE_SIZE, ColorType::Rgb8)?;
PngEncoder::new(cursor).write_image(image.as_bytes(), IMAGE_SIZE, IMAGE_SIZE, ExtendedColorType::Rgb8)?;
Ok(out)
}

Expand Down
Loading