kovi_plugin_copycat/
lib.rs1mod 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}