Compare commits
14 Commits
6ba374801f
...
4cbc8c0030
Author | SHA1 | Date |
---|---|---|
Harsh Shandilya | 4cbc8c0030 | |
Harsh Shandilya | b689a6e698 | |
Harsh Shandilya | d928d6947c | |
Harsh Shandilya | b38af61ec9 | |
Harsh Shandilya | e324a82e34 | |
Harsh Shandilya | a297ef7074 | |
Harsh Shandilya | 3e5e0550f3 | |
Harsh Shandilya | 2e8c824686 | |
Harsh Shandilya | e03ef7a607 | |
Harsh Shandilya | 775d8378f3 | |
GitHub Actions | 669bce3f52 | |
renovate[bot] | 46e19af1f5 | |
renovate[bot] | 67ec88a3e8 | |
renovate[bot] | 81ab49659b |
|
@ -14,7 +14,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||||
|
|
||||||
- name: Set up flyctl
|
- name: Set up flyctl
|
||||||
uses: superfly/flyctl-actions/setup-flyctl@master
|
uses: superfly/flyctl-actions/setup-flyctl@master
|
||||||
|
|
|
@ -394,9 +394,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.28"
|
version = "1.0.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
|
checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
|
@ -705,7 +705,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"hyper 0.14.28",
|
"hyper 0.14.28",
|
||||||
"rustls 0.21.11",
|
"rustls 0.21.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.24.1",
|
"tokio-rustls 0.24.1",
|
||||||
]
|
]
|
||||||
|
@ -1239,7 +1239,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustls 0.21.11",
|
"rustls 0.21.12",
|
||||||
"rustls-pemfile 1.0.4",
|
"rustls-pemfile 1.0.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1332,9 +1332,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.21.11"
|
version = "0.21.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4"
|
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ring",
|
"ring",
|
||||||
|
@ -1770,7 +1770,7 @@ version = "0.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls 0.21.11",
|
"rustls 0.21.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2339,6 +2339,6 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.8.0"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63381fa6624bf92130a6b87c0d07380116f80b565c42cf0d754136f0238359ef"
|
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||||
|
|
30
flake.lock
30
flake.lock
|
@ -3,11 +3,11 @@
|
||||||
"advisory-db": {
|
"advisory-db": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1713579674,
|
"lastModified": 1714183630,
|
||||||
"narHash": "sha256-JXiXi2Egq7gHfIvigBXFSdzNsxIjk1s9fcq1ibfoD/U=",
|
"narHash": "sha256-1BVft7ggSN2XXFeXQjazU3jN9wVECd9qp2mZx/8GDMk=",
|
||||||
"owner": "rustsec",
|
"owner": "rustsec",
|
||||||
"repo": "advisory-db",
|
"repo": "advisory-db",
|
||||||
"rev": "6ab370c779c140c9cb2e7ff1367dd1b66c415409",
|
"rev": "35e7459a331d3e0c585e56dabd03006b9b354088",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -23,11 +23,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1713459701,
|
"lastModified": 1713979152,
|
||||||
"narHash": "sha256-LjQ11ASxnv/FXfb8QnrIyMkyqSqcBPX+lFK8gu0jSQE=",
|
"narHash": "sha256-apdecPuh8SOQnkEET/kW/UcfjCRb8JbV5BKjoH+DcP4=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "45ea0059fb325132fdc3c39faffb0941d25d08d3",
|
"rev": "a5eca68a2cf11adb32787fc141cddd29ac8eb79c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -67,11 +67,11 @@
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1713594079,
|
"lastModified": 1714199028,
|
||||||
"narHash": "sha256-lYWehi0cqBdsL1W4xeUnUcXw4U4aBKKCmmQrR01yqE0=",
|
"narHash": "sha256-QO3Yv3UfJRfhZE1wsHOartg+k8/Kf1BiDyfl8eEpqcE=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "3247290e1bba55878a2c62d43894d0309d29c918",
|
"rev": "055f6db376eaf544d84aa55bd5a7c70634af41ba",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -118,11 +118,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1713596654,
|
"lastModified": 1714213793,
|
||||||
"narHash": "sha256-LJbHQQ5aX1LVth2ST+Kkse/DRzgxlVhTL1rxthvyhZc=",
|
"narHash": "sha256-Yg5D5LhyAZvd3DZrQQfJAVK8K3TkUYKooFtH1ulM0mw=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "fd16bb6d3bcca96039b11aa52038fafeb6e4f4be",
|
"rev": "d6f6eb2a984f2ba9a366c31e4d36d65465683450",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -147,11 +147,11 @@
|
||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1713559870,
|
"lastModified": 1714150666,
|
||||||
"narHash": "sha256-HsVa+QM2vMra80OjnjH7JhdvLeJuMdR4sxBNHJveMe4=",
|
"narHash": "sha256-S8AsTyJvT6Q3pRFeo8QepWF/husnJh61cOhRt18Xmyc=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "c83d8cf5844fff3d6e243ab408669222059af1c6",
|
"rev": "1ed7e2de05ee76f6ae83cc9c72eb0b33ad6903f2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
152
src/commands.rs
152
src/commands.rs
|
@ -1,15 +1,21 @@
|
||||||
use crate::{message::BotExt, utils::parse_bool};
|
use crate::{
|
||||||
|
fixer::FixerState,
|
||||||
|
message::BotExt,
|
||||||
|
utils::{parse_bool, AsyncError},
|
||||||
|
FIXER_STATE,
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{env, error::Error, marker::Send};
|
use std::env;
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
payloads::SendMessageSetters,
|
payloads::SendMessageSetters,
|
||||||
prelude::Requester,
|
prelude::Requester,
|
||||||
types::{Message, UserId},
|
types::{ChatAction, Message, UserId},
|
||||||
utils::command::BotCommands,
|
utils::command::BotCommands,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) type FilterState = String;
|
pub(crate) type FilterState = String;
|
||||||
|
|
||||||
static BOT_OWNER: Lazy<UserId> = Lazy::new(|| {
|
static BOT_OWNER: Lazy<UserId> = Lazy::new(|| {
|
||||||
let value = env::var("BOT_OWNER_ID").expect("BOT_OWNER_ID must be defined");
|
let value = env::var("BOT_OWNER_ID").expect("BOT_OWNER_ID must be defined");
|
||||||
let id = value
|
let id = value
|
||||||
|
@ -43,58 +49,96 @@ pub(crate) enum Command {
|
||||||
YouTube { filter_state: FilterState },
|
YouTube { filter_state: FilterState },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_authorized(bot: &Bot, message: &Message) -> Result<bool, AsyncError> {
|
||||||
|
let admins = bot.get_chat_administrators(message.chat.id).await;
|
||||||
|
let admins = match admins {
|
||||||
|
Ok(admins) => admins,
|
||||||
|
Err(e) => {
|
||||||
|
return Ok(e
|
||||||
|
.to_string()
|
||||||
|
.contains("there are no administrators in the private chat"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let admins = admins.iter().map(|c| c.user.clone()).collect::<Vec<_>>();
|
||||||
|
let from = message.from().ok_or("No user found")?;
|
||||||
|
Ok(from.id == *BOT_OWNER || admins.contains(from))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_fixer_state<F>(message: &Message, update_state: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut FixerState) -> () + Copy,
|
||||||
|
{
|
||||||
|
if let Ok(ref mut map) = FIXER_STATE.try_lock() {
|
||||||
|
map.entry(message.chat.id)
|
||||||
|
.and_modify(|e| update_state(e))
|
||||||
|
.or_insert_with(|| {
|
||||||
|
let mut state = FixerState::default();
|
||||||
|
update_state(&mut state);
|
||||||
|
state
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn handler(
|
pub(crate) async fn handler(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
message: Message,
|
message: Message,
|
||||||
command: Command,
|
command: Command,
|
||||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
) -> Result<(), AsyncError> {
|
||||||
match command {
|
match command {
|
||||||
Command::Help | Command::Start => {
|
Command::Help | Command::Start => {
|
||||||
bot.send_chat_message(message, Command::descriptions().to_string())
|
bot.send_chat_message(&message, Command::descriptions().to_string())
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Command::Ping => {
|
Command::Ping => {
|
||||||
bot.send_chat_message(message, "Pong".to_string()).await?;
|
bot.send_chat_message(&message, "Pong".to_string()).await?;
|
||||||
}
|
}
|
||||||
#[cfg(feature = "ddinstagram")]
|
#[cfg(feature = "ddinstagram")]
|
||||||
Command::Instagram { filter_state } => {
|
Command::Instagram { filter_state } => {
|
||||||
if let Some(from) = message.from()
|
if check_authorized(&bot, &message).await? {
|
||||||
&& from.id != *BOT_OWNER
|
|
||||||
{
|
|
||||||
bot.send_chat_message(
|
|
||||||
message,
|
|
||||||
"You are not authorized for this action".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
match parse_bool(&filter_state) {
|
match parse_bool(&filter_state) {
|
||||||
Ok(filter_state) => {
|
Ok(filter_state) => {
|
||||||
crate::instagram::set_filter_state(bot, message, filter_state).await?;
|
update_fixer_state(&message, |x| x.instagram(filter_state));
|
||||||
|
let state = if filter_state { "enabled" } else { "disabled" };
|
||||||
|
bot.send_chat_message(
|
||||||
|
&message,
|
||||||
|
format!("Instagram link replacement is now {}", state),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Err(error_message) => {
|
Err(error_message) => {
|
||||||
bot.send_chat_message(message, error_message).await?;
|
bot.send_chat_message(&message, error_message).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
||||||
|
.await?;
|
||||||
|
bot.send_message(message.chat.id, "You are not authorized for this action")
|
||||||
|
.reply_to_message_id(message.id)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::Medium { filter_state } => {
|
Command::Medium { filter_state } => {
|
||||||
if let Some(from) = message.from()
|
if check_authorized(&bot, &message).await? {
|
||||||
&& from.id != *BOT_OWNER
|
|
||||||
{
|
|
||||||
bot.send_chat_message(
|
|
||||||
message,
|
|
||||||
"You are not authorized for this action".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
match parse_bool(&filter_state) {
|
match parse_bool(&filter_state) {
|
||||||
Ok(filter_state) => {
|
Ok(filter_state) => {
|
||||||
crate::medium::set_filter_state(bot, message, filter_state).await?;
|
update_fixer_state(&message, |x| x.medium(filter_state));
|
||||||
|
let state = if filter_state { "enabled" } else { "disabled" };
|
||||||
|
bot.send_chat_message(
|
||||||
|
&message,
|
||||||
|
format!("Medium link replacement is now {}", state),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Err(error_message) => {
|
Err(error_message) => {
|
||||||
bot.send_chat_message(message, error_message).await?;
|
bot.send_chat_message(&message, error_message).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
||||||
|
.await?;
|
||||||
|
bot.send_message(message.chat.id, "You are not authorized for this action")
|
||||||
|
.reply_to_message_id(message.id)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::Ttv { names } => {
|
Command::Ttv { names } => {
|
||||||
|
@ -104,43 +148,51 @@ pub(crate) async fn handler(
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Command::Twitter { filter_state } => {
|
Command::Twitter { filter_state } => {
|
||||||
if let Some(from) = message.from()
|
if check_authorized(&bot, &message).await? {
|
||||||
&& from.id != *BOT_OWNER
|
|
||||||
{
|
|
||||||
bot.send_chat_message(
|
|
||||||
message,
|
|
||||||
"You are not authorized for this action".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
match parse_bool(&filter_state) {
|
match parse_bool(&filter_state) {
|
||||||
Ok(filter_state) => {
|
Ok(filter_state) => {
|
||||||
crate::twitter::set_filter_state(bot, message, filter_state).await?;
|
update_fixer_state(&message, |x| x.twitter(filter_state));
|
||||||
|
let state = if filter_state { "enabled" } else { "disabled" };
|
||||||
|
bot.send_chat_message(
|
||||||
|
&message,
|
||||||
|
format!("Twitter link replacement is now {}", state),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Err(error_message) => {
|
Err(error_message) => {
|
||||||
bot.send_chat_message(message, error_message).await?;
|
bot.send_chat_message(&message, error_message).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
||||||
|
.await?;
|
||||||
|
bot.send_message(message.chat.id, "You are not authorized for this action")
|
||||||
|
.reply_to_message_id(message.id)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::YouTube { filter_state } => {
|
Command::YouTube { filter_state } => {
|
||||||
if let Some(from) = message.from()
|
if check_authorized(&bot, &message).await? {
|
||||||
&& from.id != *BOT_OWNER
|
|
||||||
{
|
|
||||||
bot.send_chat_message(
|
|
||||||
message,
|
|
||||||
"You are not authorized for this action".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
match parse_bool(&filter_state) {
|
match parse_bool(&filter_state) {
|
||||||
Ok(filter_state) => {
|
Ok(filter_state) => {
|
||||||
crate::youtube::set_filter_state(bot, message, filter_state).await?;
|
update_fixer_state(&message, |x| x.youtube(filter_state));
|
||||||
|
let state = if filter_state { "enabled" } else { "disabled" };
|
||||||
|
bot.send_chat_message(
|
||||||
|
&message,
|
||||||
|
format!("YouTube link replacement is now {}", state),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Err(error_message) => {
|
Err(error_message) => {
|
||||||
bot.send_chat_message(message, error_message).await?;
|
bot.send_chat_message(&message, error_message).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
||||||
|
.await?;
|
||||||
|
bot.send_message(message.chat.id, "You are not authorized for this action")
|
||||||
|
.reply_to_message_id(message.id)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
mod model;
|
mod model;
|
||||||
|
|
||||||
use crate::{message::BotExt, utils::get_urls_from_message};
|
use crate::{
|
||||||
|
message::BotExt,
|
||||||
|
utils::{get_urls_from_message, AsyncError},
|
||||||
|
};
|
||||||
use model::AMPResponse;
|
use model::AMPResponse;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use std::{error::Error, str::FromStr};
|
use std::str::FromStr;
|
||||||
use teloxide::{prelude::Requester, types::Message, utils::html::link, Bot};
|
use teloxide::{prelude::Requester, types::Message, utils::html::link, Bot};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
@ -13,10 +16,7 @@ fn deserialize_amp_response(text: &str) -> Result<AMPResponse, serde_json::Error
|
||||||
serde_json::from_str(text)
|
serde_json::from_str(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handler(
|
pub async fn handler(bot: Bot, message: Message) -> Result<(), AsyncError> {
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
if let Some(text) = message.text()
|
if let Some(text) = message.text()
|
||||||
&& let Some(user) = message.from()
|
&& let Some(user) = message.from()
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ pub async fn handler(
|
||||||
}
|
}
|
||||||
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
||||||
let _del = bot.delete_message(message.chat.id, message.id).await;
|
let _del = bot.delete_message(message.chat.id, message.id).await;
|
||||||
bot.try_reply(message, text).await?;
|
bot.try_reply(&message, text).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#[allow(clippy::struct_excessive_bools)] // Does not apply
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(crate) struct FixerState {
|
||||||
|
pub(crate) instagram: bool,
|
||||||
|
pub(crate) medium: bool,
|
||||||
|
pub(crate) twitter: bool,
|
||||||
|
pub(crate) youtube: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FixerState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
instagram: true,
|
||||||
|
medium: true,
|
||||||
|
twitter: true,
|
||||||
|
youtube: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FixerState {
|
||||||
|
pub(crate) fn instagram(&mut self, value: bool) {
|
||||||
|
self.instagram = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn medium(&mut self, value: bool) {
|
||||||
|
self.medium = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn twitter(&mut self, value: bool) {
|
||||||
|
self.twitter = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn youtube(&mut self, value: bool) {
|
||||||
|
self.youtube = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,10 @@
|
||||||
use crate::{message::BotExt, utils::scrub_urls};
|
use crate::{
|
||||||
|
message::BotExt,
|
||||||
|
utils::{scrub_urls, AsyncError},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use teloxide::{prelude::Requester, types::Message, utils::html::link, Bot};
|
||||||
error::Error,
|
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
|
||||||
};
|
|
||||||
use teloxide::{
|
|
||||||
payloads::SendMessageSetters,
|
|
||||||
prelude::Requester,
|
|
||||||
types::{ChatAction, Message},
|
|
||||||
utils::html::link,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
const HOST_MATCH_GROUP: &str = "host";
|
const HOST_MATCH_GROUP: &str = "host";
|
||||||
|
|
||||||
|
@ -19,49 +12,7 @@ pub static MATCH_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||||
Regex::new("https://(?:www.)?(?P<host>instagram.com)/(p|reel|tv)/[A-Za-z0-9]+.*/").unwrap()
|
Regex::new("https://(?:www.)?(?P<host>instagram.com)/(p|reel|tv)/[A-Za-z0-9]+.*/").unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static FILTER_ENABLED: AtomicBool = AtomicBool::new(true);
|
pub async fn handler(bot: Bot, message: Message) -> Result<(), AsyncError> {
|
||||||
|
|
||||||
pub async fn set_filter_state(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
filter_state: Option<bool>,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
match filter_state {
|
|
||||||
None => {
|
|
||||||
let state = if FILTER_ENABLED.load(Ordering::Relaxed) {
|
|
||||||
"enabled"
|
|
||||||
} else {
|
|
||||||
"disabled"
|
|
||||||
};
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("Instagram link replacement is {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Some(state) => {
|
|
||||||
FILTER_ENABLED.store(state, Ordering::Relaxed);
|
|
||||||
let state = if state { "enabled" } else { "disabled" };
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("Instagram link replacement has been {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handler(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
if let Some(text) = scrub_urls(&message)
|
if let Some(text) = scrub_urls(&message)
|
||||||
&& let Some(user) = message.from()
|
&& let Some(user) = message.from()
|
||||||
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
||||||
|
@ -69,7 +20,7 @@ pub async fn handler(
|
||||||
let text = text.replace(&caps[HOST_MATCH_GROUP], "ddinstagram.com");
|
let text = text.replace(&caps[HOST_MATCH_GROUP], "ddinstagram.com");
|
||||||
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
||||||
let _del = bot.delete_message(message.chat.id, message.id).await;
|
let _del = bot.delete_message(message.chat.id, message.id).await;
|
||||||
bot.try_reply(message, text).await?;
|
bot.try_reply(&message, text).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
98
src/main.rs
98
src/main.rs
|
@ -1,6 +1,7 @@
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
mod commands;
|
mod commands;
|
||||||
mod deamp;
|
mod deamp;
|
||||||
|
mod fixer;
|
||||||
#[cfg(feature = "ddinstagram")]
|
#[cfg(feature = "ddinstagram")]
|
||||||
mod instagram;
|
mod instagram;
|
||||||
mod logging;
|
mod logging;
|
||||||
|
@ -13,16 +14,23 @@ mod youtube;
|
||||||
use crate::commands::Command;
|
use crate::commands::Command;
|
||||||
use crate::logging::TeloxideLogger;
|
use crate::logging::TeloxideLogger;
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
use std::sync::{atomic::Ordering, Arc};
|
use fixer::FixerState;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
dispatching::{HandlerExt, UpdateFilterExt},
|
dispatching::{dialogue::GetChatId, HandlerExt, UpdateFilterExt},
|
||||||
dptree,
|
dptree,
|
||||||
prelude::Dispatcher,
|
prelude::Dispatcher,
|
||||||
types::{Message, Update},
|
types::{ChatId, Message, Update},
|
||||||
update_listeners::Polling,
|
update_listeners::Polling,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) static FIXER_STATE: Lazy<Mutex<HashMap<ChatId, FixerState>>> =
|
||||||
|
Lazy::new(|| Mutex::new(HashMap::new()));
|
||||||
const REPLACE_SKIP_TOKEN: &str = "#skip";
|
const REPLACE_SKIP_TOKEN: &str = "#skip";
|
||||||
|
|
||||||
async fn run() {
|
async fn run() {
|
||||||
|
@ -42,51 +50,77 @@ async fn run() {
|
||||||
)
|
)
|
||||||
.branch(
|
.branch(
|
||||||
dptree::filter(|msg: Message| {
|
dptree::filter(|msg: Message| {
|
||||||
twitter::FILTER_ENABLED.load(Ordering::Relaxed)
|
if let Ok(ref mut map) = FIXER_STATE.try_lock()
|
||||||
&& msg
|
&& let Some(chat_id) = msg.chat_id()
|
||||||
.text()
|
{
|
||||||
.map(|text| {
|
let state = map.entry(chat_id).or_insert(FixerState::default());
|
||||||
twitter::MATCH_REGEX.is_match(text)
|
return state.twitter
|
||||||
&& !text.contains(REPLACE_SKIP_TOKEN)
|
&& msg
|
||||||
})
|
.text()
|
||||||
.unwrap_or_default()
|
.map(|text| {
|
||||||
|
twitter::MATCH_REGEX.is_match(text)
|
||||||
|
&& !text.contains(REPLACE_SKIP_TOKEN)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
false
|
||||||
})
|
})
|
||||||
.endpoint(twitter::handler),
|
.endpoint(twitter::handler),
|
||||||
);
|
);
|
||||||
#[cfg(feature = "ddinstagram")]
|
#[cfg(feature = "ddinstagram")]
|
||||||
let handler = handler.branch(
|
let handler = handler.branch(
|
||||||
dptree::filter(|msg: Message| {
|
dptree::filter(|msg: Message| {
|
||||||
instagram::FILTER_ENABLED.load(Ordering::Relaxed)
|
if let Ok(ref mut map) = FIXER_STATE.try_lock()
|
||||||
&& msg
|
&& let Some(chat_id) = msg.chat_id()
|
||||||
.text()
|
{
|
||||||
.map(|text| {
|
let state = map.entry(chat_id).or_insert(FixerState::default());
|
||||||
instagram::MATCH_REGEX.is_match(text) && !text.contains(REPLACE_SKIP_TOKEN)
|
return state.instagram
|
||||||
})
|
&& msg
|
||||||
.unwrap_or_default()
|
.text()
|
||||||
|
.map(|text| {
|
||||||
|
instagram::MATCH_REGEX.is_match(text)
|
||||||
|
&& !text.contains(REPLACE_SKIP_TOKEN)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
false
|
||||||
})
|
})
|
||||||
.endpoint(instagram::handler),
|
.endpoint(instagram::handler),
|
||||||
);
|
);
|
||||||
let handler = handler.branch(
|
let handler = handler.branch(
|
||||||
dptree::filter(|msg: Message| {
|
dptree::filter(|msg: Message| {
|
||||||
youtube::FILTER_ENABLED.load(Ordering::Relaxed)
|
if let Ok(ref mut map) = FIXER_STATE.try_lock()
|
||||||
&& msg
|
&& let Some(chat_id) = msg.chat_id()
|
||||||
.text()
|
{
|
||||||
.map(|text| {
|
let state = map.entry(chat_id).or_insert(FixerState::default());
|
||||||
youtube::MATCH_REGEX.is_match(text) && !text.contains(REPLACE_SKIP_TOKEN)
|
return state.youtube
|
||||||
})
|
&& msg
|
||||||
.unwrap_or_default()
|
.text()
|
||||||
|
.map(|text| {
|
||||||
|
youtube::MATCH_REGEX.is_match(text)
|
||||||
|
&& !text.contains(REPLACE_SKIP_TOKEN)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
false
|
||||||
})
|
})
|
||||||
.endpoint(youtube::handler),
|
.endpoint(youtube::handler),
|
||||||
);
|
);
|
||||||
let handler = handler.branch(
|
let handler = handler.branch(
|
||||||
dptree::filter(|msg: Message| {
|
dptree::filter(|msg: Message| {
|
||||||
medium::FILTER_ENABLED.load(Ordering::Relaxed)
|
if let Ok(ref mut map) = FIXER_STATE.try_lock()
|
||||||
&& msg
|
&& let Some(chat_id) = msg.chat_id()
|
||||||
.text()
|
{
|
||||||
.map(|text| {
|
let state = map.entry(chat_id).or_insert(FixerState::default());
|
||||||
medium::MATCH_REGEX.is_match(text) && !text.contains(REPLACE_SKIP_TOKEN)
|
return state.medium
|
||||||
})
|
&& msg
|
||||||
.unwrap_or_default()
|
.text()
|
||||||
|
.map(|text| {
|
||||||
|
medium::MATCH_REGEX.is_match(text) && !text.contains(REPLACE_SKIP_TOKEN)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
false
|
||||||
})
|
})
|
||||||
.endpoint(medium::handler),
|
.endpoint(medium::handler),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,66 +1,17 @@
|
||||||
use crate::{message::BotExt, utils::scrub_urls};
|
use crate::{
|
||||||
|
message::BotExt,
|
||||||
|
utils::{scrub_urls, AsyncError},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use teloxide::{prelude::Requester, types::Message, utils::html::link, Bot};
|
||||||
error::Error,
|
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
|
||||||
};
|
|
||||||
use teloxide::{
|
|
||||||
payloads::SendMessageSetters,
|
|
||||||
prelude::Requester,
|
|
||||||
types::{ChatAction, Message},
|
|
||||||
utils::html::link,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
const HOST_MATCH_GROUP: &str = "host";
|
const HOST_MATCH_GROUP: &str = "host";
|
||||||
|
|
||||||
pub static MATCH_REGEX: Lazy<Regex> =
|
pub static MATCH_REGEX: Lazy<Regex> =
|
||||||
Lazy::new(|| Regex::new("https://(?P<host>(?:.*)?medium.com)/.*").unwrap());
|
Lazy::new(|| Regex::new("https://(?P<host>(?:.*)?medium.com)/.*").unwrap());
|
||||||
|
|
||||||
pub static FILTER_ENABLED: AtomicBool = AtomicBool::new(true);
|
pub async fn handler(bot: Bot, message: Message) -> Result<(), AsyncError> {
|
||||||
|
|
||||||
pub async fn set_filter_state(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
filter_state: Option<bool>,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
match filter_state {
|
|
||||||
None => {
|
|
||||||
let state = if FILTER_ENABLED.load(Ordering::Relaxed) {
|
|
||||||
"enabled"
|
|
||||||
} else {
|
|
||||||
"disabled"
|
|
||||||
};
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("Medium link replacement is {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Some(state) => {
|
|
||||||
FILTER_ENABLED.store(state, Ordering::Relaxed);
|
|
||||||
let state = if state { "enabled" } else { "disabled" };
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("Medium link replacement has been {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handler(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
if let Some(text) = scrub_urls(&message)
|
if let Some(text) = scrub_urls(&message)
|
||||||
&& let Some(user) = message.from()
|
&& let Some(user) = message.from()
|
||||||
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
||||||
|
@ -68,7 +19,7 @@ pub async fn handler(
|
||||||
let text = text.replace(&caps[HOST_MATCH_GROUP], "medium.rip");
|
let text = text.replace(&caps[HOST_MATCH_GROUP], "medium.rip");
|
||||||
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
||||||
let _del = bot.delete_message(message.chat.id, message.id).await;
|
let _del = bot.delete_message(message.chat.id, message.id).await;
|
||||||
bot.try_reply(message, text).await?;
|
bot.try_reply(&message, text).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,16 @@ use teloxide::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) trait BotExt {
|
pub(crate) trait BotExt {
|
||||||
async fn try_reply(&self, message: Message, text: String) -> Result<Message, RequestError>;
|
async fn try_reply(&self, message: &Message, text: String) -> Result<Message, RequestError>;
|
||||||
async fn send_chat_message(
|
async fn send_chat_message(
|
||||||
&self,
|
&self,
|
||||||
message: Message,
|
message: &Message,
|
||||||
text: String,
|
text: String,
|
||||||
) -> Result<Message, RequestError>;
|
) -> Result<Message, RequestError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BotExt for Bot {
|
impl BotExt for Bot {
|
||||||
async fn try_reply(&self, message: Message, text: String) -> Result<Message, RequestError> {
|
async fn try_reply(&self, message: &Message, text: String) -> Result<Message, RequestError> {
|
||||||
if let Some(reply) = message.reply_to_message() {
|
if let Some(reply) = message.reply_to_message() {
|
||||||
self.send_message(message.chat.id, text)
|
self.send_message(message.chat.id, text)
|
||||||
.reply_to_message_id(reply.id)
|
.reply_to_message_id(reply.id)
|
||||||
|
@ -30,7 +30,7 @@ impl BotExt for Bot {
|
||||||
|
|
||||||
async fn send_chat_message(
|
async fn send_chat_message(
|
||||||
&self,
|
&self,
|
||||||
message: Message,
|
message: &Message,
|
||||||
text: String,
|
text: String,
|
||||||
) -> Result<Message, RequestError> {
|
) -> Result<Message, RequestError> {
|
||||||
self.send_chat_action(message.chat.id, ChatAction::Typing)
|
self.send_chat_action(message.chat.id, ChatAction::Typing)
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
use crate::{message::BotExt, utils::scrub_urls};
|
use crate::{
|
||||||
|
message::BotExt,
|
||||||
|
utils::{scrub_urls, AsyncError},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use teloxide::{prelude::Requester, types::Message, utils::html::link, Bot};
|
||||||
error::Error,
|
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
|
||||||
};
|
|
||||||
use teloxide::{
|
|
||||||
payloads::SendMessageSetters,
|
|
||||||
prelude::Requester,
|
|
||||||
types::{ChatAction, Message},
|
|
||||||
utils::html::link,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
const HOST_MATCH_GROUP: &str = "host";
|
const HOST_MATCH_GROUP: &str = "host";
|
||||||
const ROOT_MATCH_GROUP: &str = "root";
|
const ROOT_MATCH_GROUP: &str = "root";
|
||||||
|
@ -21,49 +14,7 @@ pub static MATCH_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static FILTER_ENABLED: AtomicBool = AtomicBool::new(true);
|
pub async fn handler(bot: Bot, message: Message) -> Result<(), AsyncError> {
|
||||||
|
|
||||||
pub async fn set_filter_state(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
filter_state: Option<bool>,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
match filter_state {
|
|
||||||
None => {
|
|
||||||
let state = if FILTER_ENABLED.load(Ordering::Relaxed) {
|
|
||||||
"enabled"
|
|
||||||
} else {
|
|
||||||
"disabled"
|
|
||||||
};
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("Twitter link replacement is {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Some(state) => {
|
|
||||||
FILTER_ENABLED.store(state, Ordering::Relaxed);
|
|
||||||
let state = if state { "enabled" } else { "disabled" };
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("Twitter link replacement has been {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handler(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
if let Some(text) = scrub_urls(&message)
|
if let Some(text) = scrub_urls(&message)
|
||||||
&& let Some(user) = message.from()
|
&& let Some(user) = message.from()
|
||||||
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
||||||
|
@ -78,7 +29,7 @@ pub async fn handler(
|
||||||
};
|
};
|
||||||
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
||||||
let _del = bot.delete_message(message.chat.id, message.id).await;
|
let _del = bot.delete_message(message.chat.id, message.id).await;
|
||||||
bot.try_reply(message, text).await?;
|
bot.try_reply(&message, text).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
10
src/utils.rs
10
src/utils.rs
|
@ -1,8 +1,11 @@
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
|
use std::error::Error;
|
||||||
use teloxide::types::{Message, MessageEntityKind};
|
use teloxide::types::{Message, MessageEntityKind};
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
pub(crate) type AsyncError = Box<dyn Error + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub(crate) fn get_urls_from_message(msg: &Message) -> Vec<String> {
|
pub(crate) fn get_urls_from_message(msg: &Message) -> Vec<String> {
|
||||||
if let Some(entities) = msg.entities()
|
if let Some(entities) = msg.entities()
|
||||||
&& !entities.is_empty()
|
&& !entities.is_empty()
|
||||||
|
@ -51,7 +54,7 @@ pub(crate) fn scrub_urls(msg: &Message) -> Option<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_bool(input: &str) -> Result<Option<bool>, String> {
|
pub(crate) fn parse_bool(input: &str) -> Result<bool, String> {
|
||||||
const TRUE_VALUES: [&str; 4] = ["true", "on", "yes", "enable"];
|
const TRUE_VALUES: [&str; 4] = ["true", "on", "yes", "enable"];
|
||||||
const FALSE_VALUES: [&str; 4] = ["false", "off", "no", "disable"];
|
const FALSE_VALUES: [&str; 4] = ["false", "off", "no", "disable"];
|
||||||
static EXPECTED_VALUES: Lazy<String> = Lazy::new(|| {
|
static EXPECTED_VALUES: Lazy<String> = Lazy::new(|| {
|
||||||
|
@ -72,9 +75,8 @@ pub(crate) fn parse_bool(input: &str) -> Result<Option<bool>, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match input[0].to_lowercase().as_str() {
|
match input[0].to_lowercase().as_str() {
|
||||||
arg if TRUE_VALUES.contains(&arg) => Ok(Some(true)),
|
arg if TRUE_VALUES.contains(&arg) => Ok(true),
|
||||||
arg if FALSE_VALUES.contains(&arg) => Ok(Some(false)),
|
arg if FALSE_VALUES.contains(&arg) => Ok(false),
|
||||||
"" => Ok(None),
|
|
||||||
arg => {
|
arg => {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"Unexpected argument '{arg}'. Expected one of: {}.",
|
"Unexpected argument '{arg}'. Expected one of: {}.",
|
||||||
|
|
|
@ -1,65 +1,16 @@
|
||||||
use crate::{message::BotExt, utils::scrub_urls};
|
use crate::{
|
||||||
|
message::BotExt,
|
||||||
|
utils::{scrub_urls, AsyncError},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use teloxide::{prelude::Requester, types::Message, utils::html::link, Bot};
|
||||||
error::Error,
|
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
|
||||||
};
|
|
||||||
use teloxide::{
|
|
||||||
payloads::SendMessageSetters,
|
|
||||||
prelude::Requester,
|
|
||||||
types::{ChatAction, Message},
|
|
||||||
utils::html::link,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub static MATCH_REGEX: Lazy<Regex> = Lazy::new(|| {
|
pub static MATCH_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||||
Regex::new("https://(?:www.)?youtube.com/(?P<shorts>shorts/)[A-Za-z0-9-_]{11}.*").unwrap()
|
Regex::new("https://(?:www.)?youtube.com/(?P<shorts>shorts/)[A-Za-z0-9-_]{11}.*").unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static FILTER_ENABLED: AtomicBool = AtomicBool::new(true);
|
pub async fn handler(bot: Bot, message: Message) -> Result<(), AsyncError> {
|
||||||
|
|
||||||
pub async fn set_filter_state(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
filter_state: Option<bool>,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
match filter_state {
|
|
||||||
None => {
|
|
||||||
let state = if FILTER_ENABLED.load(Ordering::Relaxed) {
|
|
||||||
"enabled"
|
|
||||||
} else {
|
|
||||||
"disabled"
|
|
||||||
};
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("YouTube link replacement is {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Some(state) => {
|
|
||||||
FILTER_ENABLED.store(state, Ordering::Relaxed);
|
|
||||||
let state = if state { "enabled" } else { "disabled" };
|
|
||||||
bot.send_chat_action(message.chat.id, ChatAction::Typing)
|
|
||||||
.await?;
|
|
||||||
bot.send_message(
|
|
||||||
message.chat.id,
|
|
||||||
format!("YouTube link replacement has been {state}"),
|
|
||||||
)
|
|
||||||
.reply_to_message_id(message.id)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handler(
|
|
||||||
bot: Bot,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<(), Box<dyn Error + Sync + Send + 'static>> {
|
|
||||||
if let Some(text) = scrub_urls(&message)
|
if let Some(text) = scrub_urls(&message)
|
||||||
&& let Some(user) = message.from()
|
&& let Some(user) = message.from()
|
||||||
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
&& let Some(caps) = MATCH_REGEX.captures(&text)
|
||||||
|
@ -67,7 +18,7 @@ pub async fn handler(
|
||||||
let text = text.replace(&caps["shorts"], "watch?v=");
|
let text = text.replace(&caps["shorts"], "watch?v=");
|
||||||
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
let text = format!("{}: {}", link(user.url().as_str(), &user.full_name()), text);
|
||||||
let _del = bot.delete_message(message.chat.id, message.id).await;
|
let _del = bot.delete_message(message.chat.id, message.id).await;
|
||||||
bot.try_reply(message, text).await?;
|
bot.try_reply(&message, text).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue