1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
//! Requires the "cache", "methods", and "voice" features be enabled in your
//! Cargo.toml, like so:
//!
//! ```toml
//! [dependencies.serenity]
//! version = "*"
//! features = ["cache", "framework"]
//! ```
//!
//! Note that - due to bot users not being able to search - this example may
//! only be run under a user account.
//!
//! This particular example will automatically ensure that only the current user
//! may search; this acts as a "selfbot".
#[macro_use]
extern crate serenity;
use serenity::client::{CACHE, Client, Context};
use serenity::model::Message;
use serenity::utils::builder::{SortingMode, SortingOrder};
use std::env;
fn main() {
let mut client = Client::login_user(&env::var("DISCORD_TOKEN").unwrap());
client.with_framework(|f| f
.configure(|c| c.prefix("~").on_mention(true))
.command("search", |c| c
.exec(search)
.check(self_check)));
client.on_ready(|_context, ready| {
println!("{} is connected!", ready.user.name);
});
if let Err(why) = client.start() {
println!("Client error: {:?}", why);
}
}
fn self_check(_context: &mut Context, message: &Message) -> bool {
message.author.id == CACHE.read().unwrap().user.id
}
command!(search(context, message, args) {
let query = args.join(" ");
if query.is_empty() {
let _ = context.say("You must provide a query");
return Ok(());
}
let guild_id = match message.guild_id() {
Some(guild_id) => guild_id,
None => {
let _ = context.say("Only supports guilds");
return Ok(());
},
};
let channel_ids = {
let cache = CACHE.read().unwrap();
let guild = match cache.get_guild(guild_id) {
Some(guild) => guild,
None => {
let _ = context.say("Guild data not found");
return Ok(());
},
};
let channel_ids = guild.read().unwrap()
.channels
.values()
.filter(|c| c.read().unwrap().name.starts_with("search-"))
.map(|c| c.read().unwrap().id)
.collect::<Vec<_>>();
channel_ids.clone()
};
let search = guild_id.search_channels(&channel_ids, |s| s
.content(&query)
.context_size(0)
.has_attachment(true)
.has_embed(true)
.max_id(message.id.0 - 1)
.sort_by(SortingMode::Timestamp)
.sort_order(SortingOrder::Descending));
let messages = match search {
Ok(messages) => messages,
Err(why) => {
println!("Error performing search '{}': {:?}", query, why);
let _ = context.say("Error occurred while searching");
return Ok(());
},
};
let _ = context.send_message(|m| m
.content(&format!("Found {} total results", messages.total))
.embed(move |mut e| {
for (i, mut messages) in messages.results.into_iter().enumerate() {
let mut message = &mut messages[0];
message.content.truncate(1000);
e = e.field(|f| f
.name(&format!("Result {}", i))
.value(&message.content));
}
e
}));
});
|