From 2b3159114ad2927a4b40db7416e7a55d28c313b5 Mon Sep 17 00:00:00 2001 From: AndrielFR Date: Mon, 6 Jan 2025 23:53:42 -0300 Subject: [PATCH] feat(filters): impl `has_url` to check for urls - rename all check-related filter with prefix 'has'. --- lib/ferogram/Cargo.toml | 10 +- lib/ferogram/src/filters/mod.rs | 161 +++++++++++++++++++++++--------- 2 files changed, 124 insertions(+), 47 deletions(-) diff --git a/lib/ferogram/Cargo.toml b/lib/ferogram/Cargo.toml index c0a79a2..bd87a0d 100644 --- a/lib/ferogram/Cargo.toml +++ b/lib/ferogram/Cargo.toml @@ -16,12 +16,13 @@ edition = "2021" doctest = false [features] -default = ["macros"] +default = ["macros", "url"] -macros = ["ferogram-macros"] +macros = ["dep:ferogram-macros"] -lua = ["mlua"] -python = ["pyo3", "pyo3-async-runtimes"] +lua = ["dep:mlua"] +url = ["dep:url"] +python = ["dep:pyo3", "dep:pyo3-async-runtimes"] [dependencies] ferogram-macros = { path = "../ferogram-macros", version = "0.1.0", optional = true } @@ -29,6 +30,7 @@ grammers-client = { git = "https://github.com/Lonami/grammers.git", version = "0 grammers-mtsender = { git = "https://github.com/Lonami/grammers.git", version = "0.7.0" } log = "0.4.22" +url = { version = "^2.4", optional = true } mlua = { version = "^0.10", features = ["async", "lua54", "module"], optional = true } pyo3 = { version = "^0.23", features = ["experimental-async", "macros"], optional = true } regex = "1.11.1" diff --git a/lib/ferogram/src/filters/mod.rs b/lib/ferogram/src/filters/mod.rs index 03a8618..2001698 100644 --- a/lib/ferogram/src/filters/mod.rs +++ b/lib/ferogram/src/filters/mod.rs @@ -167,10 +167,101 @@ pub fn commands_with(pres: &'static [&'static str], pats: &'static [&'static str } } +/// Pass if the message has a url. +/// +/// Injects `Vec`: urls. +pub async fn has_url(_: Client, update: Update) -> Flow { + match update { + Update::NewMessage(message) | Update::MessageEdited(message) => { + let text = message.text(); + let mut urls = Vec::new(); + + if let Some(entities) = message.fmt_entities().cloned() { + for entity in entities + .into_iter() + .filter(|entity| matches!(entity, tl::enums::MessageEntity::Url(_))) + { + let url = text + .chars() + .skip(entity.offset() as usize) + .take(entity.length() as usize) + .collect::(); + urls.push(url); + } + } + + #[cfg(feature = "url")] + { + use url::Url; + + for part in text.split_whitespace() { + if let Ok(url) = Url::parse(part) { + let url = url.to_string(); + + if !urls.contains(&url) { + urls.push(url); + } + } + } + } + + if urls.is_empty() { + flow::break_now() + } else { + flow::continue_with(urls) + } + } + _ => flow::break_now(), + } +} + +/// Pass if the messaage has a dice. +/// +/// Injects `Dice`: message's dice. +pub async fn has_dice(_: Client, update: Update) -> Flow { + match update { + Update::NewMessage(message) | Update::MessageEdited(message) => { + if let Some(Media::Dice(dice)) = message.media() { + return flow::continue_with(dice); + } + + flow::break_now() + } + _ => flow::break_now(), + } +} + +/// Pass if the message has text or caption. +/// +/// Injects `String`: message's text. +pub async fn has_text(_: Client, update: Update) -> Flow { + match update { + Update::NewMessage(message) | Update::MessageEdited(message) => { + let text = message.text().to_string(); + if !text.is_empty() { + return flow::continue_with(text); + } + + flow::break_now() + } + Update::CallbackQuery(query) => { + if let Ok(message) = query.load_message().await { + let text = message.text().to_string(); + if !text.is_empty() { + return flow::continue_with(text); + } + } + + flow::break_now() + } + _ => flow::break_now(), + } +} + /// Pass if the message has a poll. /// /// Injects `Poll`: message's poll. -pub async fn poll(_: Client, update: Update) -> Flow { +pub async fn has_poll(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(Media::Poll(poll)) = message.media() { @@ -186,7 +277,7 @@ pub async fn poll(_: Client, update: Update) -> Flow { /// Pass if the message has an audio. /// /// Injects `Document`: message's audio. -pub async fn audio(_: Client, update: Update) -> Flow { +pub async fn has_audio(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(Media::Document(document)) = message.media() { @@ -209,7 +300,7 @@ pub async fn audio(_: Client, update: Update) -> Flow { /// Pass if the message has a photo. /// /// Injects `Photo`: message's photo. -pub async fn photo(_: Client, update: Update) -> Flow { +pub async fn has_photo(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(photo) = message.photo() { @@ -227,7 +318,7 @@ pub async fn photo(_: Client, update: Update) -> Flow { /// Pass if the message has a video. /// /// Injects `Document`: message's video. -pub async fn video(_: Client, update: Update) -> Flow { +pub async fn has_video(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(Media::Document(document)) = message.media() { @@ -248,7 +339,7 @@ pub async fn video(_: Client, update: Update) -> Flow { /// Pass if the message has a document. /// /// Injects `Document`: message's document. -pub async fn document(_: Client, update: Update) -> Flow { +pub async fn has_document(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(Media::Document(document)) = message.media() { @@ -264,7 +355,7 @@ pub async fn document(_: Client, update: Update) -> Flow { /// Pass if the message has a sticker. /// /// Injects `Sticker`: message's sticker. -pub async fn sticker(_: Client, update: Update) -> Flow { +pub async fn has_sticker(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(Media::Sticker(sticker)) = message.media() { @@ -280,7 +371,7 @@ pub async fn sticker(_: Client, update: Update) -> Flow { /// Pass if the message has an animated sticker. /// /// Injects `Document`: message's animated sticker. -pub async fn animated_sticker(_: Client, update: Update) -> Flow { +pub async fn has_animated_sticker(_: Client, update: Update) -> Flow { match update { Update::NewMessage(message) | Update::MessageEdited(message) => { if let Some(Media::Document(document)) = message.media() { @@ -295,22 +386,6 @@ pub async fn animated_sticker(_: Client, update: Update) -> Flow { } } -/// Pass if the messaage has a dice. -/// -/// Injects `Dice`: message's dice. -pub async fn dice(_: Client, update: Update) -> Flow { - match update { - Update::NewMessage(message) | Update::MessageEdited(message) => { - if let Some(Media::Dice(dice)) = message.media() { - return flow::continue_with(dice); - } - - flow::break_now() - } - _ => flow::break_now(), - } -} - /// Pass if the update is a new chat member. pub async fn new_chat_member(_: Client, update: Update) -> bool { if let Update::Raw(raw_update) = update { @@ -598,6 +673,26 @@ pub async fn reply(_: Client, update: Update) -> Flow { } } +/// Pass if the message is a reply and has a dice. +/// +/// Injects `Dice`: reply message's dice. +pub async fn reply_dice(_: Client, update: Update) -> Flow { + match update { + Update::NewMessage(message) | Update::MessageEdited(message) => { + if message.reply_to_message_id().is_some() { + let reply = message.get_reply().await.unwrap().unwrap(); + + if let Some(Media::Dice(dice)) = reply.media() { + return flow::continue_with(dice); + } + } + + flow::break_now() + } + _ => flow::break_now(), + } +} + /// Pass if the message is a reply and contains the specified text. /// /// Injects `Message`: reply message. @@ -775,23 +870,3 @@ pub async fn reply_animated_sticker(_: Client, update: Update) -> Flow { _ => flow::break_now(), } } - -/// Pass if the message is a reply and has a dice. -/// -/// Injects `Dice`: reply message's dice. -pub async fn reply_dice(_: Client, update: Update) -> Flow { - match update { - Update::NewMessage(message) | Update::MessageEdited(message) => { - if message.reply_to_message_id().is_some() { - let reply = message.get_reply().await.unwrap().unwrap(); - - if let Some(Media::Dice(dice)) = reply.media() { - return flow::continue_with(dice); - } - } - - flow::break_now() - } - _ => flow::break_now(), - } -}