kovi_plugin_copycat/
lib.rs

1mod config;
2
3use kovi::{
4    PluginBuilder as plugin, RuntimeBot, bot::runtimebot::kovi_api::SetAccessControlList,
5    event::GroupMsgEvent, log::info, tokio::sync::Mutex,
6};
7use std::{collections::HashMap, sync::Arc};
8
9use crate::config::CONFIG;
10
11const PLUGIN_NAME: &str = "kovi-plugin-copycat";
12
13struct State {
14    text: String,
15    count: u32,
16    sender: i64,
17}
18
19#[kovi::plugin]
20async fn init() {
21    let bot = plugin::get_runtime_bot();
22    let config = config::init(&bot).await.unwrap();
23
24    let state: Arc<Mutex<HashMap<i64, State>>> = Arc::new(Mutex::new(HashMap::new()));
25
26    if let Some(groups) = &config.allow_groups {
27        bot.set_plugin_access_control(PLUGIN_NAME, true).unwrap();
28        bot.set_plugin_access_control_list(
29            PLUGIN_NAME,
30            true,
31            SetAccessControlList::Adds(groups.clone()),
32        )
33        .unwrap();
34    } else {
35        bot.set_plugin_access_control(PLUGIN_NAME, false).unwrap();
36    }
37
38    plugin::on_group_msg({
39        let bot = bot.clone();
40        let state = state.clone();
41        move |e| on_group_msg(e, bot.clone(), state.clone())
42    });
43
44    info!("[copycat] Ready to reveal the essence of human beings.")
45}
46
47async fn on_group_msg(
48    event: Arc<GroupMsgEvent>,
49    bot: Arc<RuntimeBot>,
50    state: Arc<Mutex<HashMap<i64, State>>>,
51) {
52    let config = CONFIG.get().unwrap();
53
54    let msgs = event.message.get("text");
55    if msgs.len() > 1
56        || msgs.is_empty()
57        || !event.message.clone().into_iter().all(|m| m.type_ == "text")
58    {
59        info!("[copycat] Not a plain text message, ignored.");
60        return;
61    }
62
63    let msg = msgs[0].data["text"].as_str().unwrap().to_string();
64
65    {
66        let mut s = state.lock().await;
67        let s = match s.get_mut(&event.group_id) {
68            Some(s) => s,
69            None => {
70                s.insert(
71                    event.group_id,
72                    State {
73                        text: String::new(),
74                        count: 0,
75                        sender: -1,
76                    },
77                );
78                s.get_mut(&event.group_id).unwrap()
79            }
80        };
81
82        if s.text == msg {
83            if s.sender != event.sender.user_id {
84                s.count += 1;
85                info!(
86                    "[copycat] Received repeated message, current count: {} / {}",
87                    s.count, config.repeat_after
88                );
89            }
90        } else {
91            s.text = msg;
92            s.count = 1;
93            s.sender = event.sender.user_id;
94        }
95
96        if s.count == config.repeat_after {
97            bot.send_group_msg(event.group_id, &s.text);
98            s.count += 1;
99
100            info!(
101                "[copycat] Meow! Current count: {} / {}",
102                s.count, config.repeat_after
103            );
104        }
105    }
106}