mirror of
https://github.com/revanced/revanced-discord-bot.git
synced 2025-05-02 15:34:24 +02:00
feat: embeds
This commit is contained in:
parent
57693d39ed
commit
4293dd5518
@ -38,9 +38,9 @@
|
||||
"$ref": "#/$defs/channels",
|
||||
"description": "A list of channel ids. The bot will only introduce in threads under these channels."
|
||||
},
|
||||
"message": {
|
||||
"$ref": "#/$defs/message",
|
||||
"description": "The message to send when the thread has been created."
|
||||
"response": {
|
||||
"$ref": "#/$defs/response",
|
||||
"description": "The response to send when the thread has been created."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -91,9 +91,9 @@
|
||||
},
|
||||
"description": "The conditions to respond to the message."
|
||||
},
|
||||
"message": {
|
||||
"$ref": "#/$defs/message",
|
||||
"description": "The message to send when the message is responded to."
|
||||
"response": {
|
||||
"$ref": "#/$defs/response",
|
||||
"description": "The response to send when the message is responded to."
|
||||
}
|
||||
},
|
||||
"description": "The conditions to respond to a message."
|
||||
@ -128,8 +128,110 @@
|
||||
"uniqueItems": true,
|
||||
"minItems": 1
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
"embed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "The title of the embed."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "The description of the embed."
|
||||
},
|
||||
"color": {
|
||||
"type": "integer",
|
||||
"description": "The color of the embed."
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the field."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The value of the field."
|
||||
},
|
||||
"inline": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the field is inline."
|
||||
}
|
||||
},
|
||||
"description": "The field to add to the embed."
|
||||
},
|
||||
"description": "The fields to add to the embed."
|
||||
},
|
||||
"image": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "The url of the image."
|
||||
}
|
||||
},
|
||||
"description": "The image to add to the embed."
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "The url of the thumbnail."
|
||||
}
|
||||
},
|
||||
"description": "The thumbnail to add to the embed."
|
||||
},
|
||||
"author": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the author."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "The url of the author."
|
||||
},
|
||||
"icon_url": {
|
||||
"type": "string",
|
||||
"description": "The url of the author's icon."
|
||||
}
|
||||
},
|
||||
"description": "The author to add to the embed."
|
||||
},
|
||||
"footer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "The text of the footer."
|
||||
},
|
||||
"icon_url": {
|
||||
"type": "string",
|
||||
"description": "The url of the footer's icon."
|
||||
}
|
||||
},
|
||||
"description": "The footer to add to the embed."
|
||||
}
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "The message. Can be empty if the embed is not empty"
|
||||
},
|
||||
"embed": {
|
||||
"$ref": "#/$defs/embed",
|
||||
"description": "The embed to send."
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ pub struct Administrators {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Introduction {
|
||||
pub channels: Vec<u64>,
|
||||
pub message: String,
|
||||
pub response: Response,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -35,7 +35,64 @@ pub struct MessageResponder {
|
||||
pub includes: Includes,
|
||||
pub excludes: Excludes,
|
||||
pub condition: Condition,
|
||||
pub message: String,
|
||||
pub response: Response,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Response {
|
||||
pub message: Option<String>,
|
||||
pub embed: Option<Embed>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Embed {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub color: i32,
|
||||
pub fields: Vec<Field>,
|
||||
pub footer: Footer,
|
||||
pub image: Image,
|
||||
pub thumbnail: Thumbnail,
|
||||
pub author: Author,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Field {
|
||||
pub name: String,
|
||||
pub value: String,
|
||||
pub inline: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Footer {
|
||||
pub text: String,
|
||||
#[serde(rename = "icon_url")]
|
||||
pub icon_url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Image {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Thumbnail {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Author {
|
||||
pub name: String,
|
||||
#[serde(rename = "icon_url")]
|
||||
pub icon_url: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
119
src/main.rs
119
src/main.rs
@ -2,13 +2,13 @@ use std::sync::Arc;
|
||||
|
||||
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
|
||||
use configuration::BotConfiguration;
|
||||
use log::{error, info, trace, warn, LevelFilter};
|
||||
use log::{error, info, trace, LevelFilter};
|
||||
use logger::logging::SimpleLogger;
|
||||
use regex::Regex;
|
||||
use serenity::client::{Context, EventHandler};
|
||||
use serenity::model::application::command::Command;
|
||||
use serenity::model::channel::{GuildChannel, Message};
|
||||
use serenity::model::gateway::Ready;
|
||||
use serenity::model::prelude::command::Command;
|
||||
use serenity::model::prelude::interaction::{Interaction, InteractionResponseType, MessageFlags};
|
||||
use serenity::prelude::{GatewayIntents, RwLock, TypeMapKey};
|
||||
use serenity::{async_trait, Client};
|
||||
@ -47,34 +47,34 @@ impl EventHandler for Handler {
|
||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||
trace!("Created an interaction: {:?}", interaction);
|
||||
|
||||
let configuration_lock = get_configuration_lock(&ctx).await;
|
||||
let mut configuration = configuration_lock.write().await;
|
||||
|
||||
if let Interaction::ApplicationCommand(command) = interaction {
|
||||
let content = match command.data.name.as_str() {
|
||||
"reload" => {
|
||||
let member = command.member.as_ref().unwrap();
|
||||
let user_id = member.user.id.0;
|
||||
let configuration_lock = get_configuration_lock(&ctx).await;
|
||||
let mut configuration = configuration_lock.write().await;
|
||||
|
||||
let administrators = &configuration.administrators;
|
||||
let administrators = &configuration.administrators;
|
||||
let member = command.member.as_ref().unwrap();
|
||||
let user_id = member.user.id.0;
|
||||
let mut stop_command = false;
|
||||
let mut permission_granted = false;
|
||||
|
||||
let mut permission_granted = false;
|
||||
// check if the user is an administrator
|
||||
if administrators.users.iter().any(|&id| user_id == id) {
|
||||
permission_granted = true
|
||||
}
|
||||
// check if the user has an administrating role
|
||||
if !permission_granted
|
||||
&& administrators
|
||||
.roles
|
||||
.iter()
|
||||
.any(|role_id| member.roles.iter().any(|member_role| member_role == role_id))
|
||||
{
|
||||
permission_granted = true
|
||||
}
|
||||
|
||||
// check if the user is an administrator
|
||||
if administrators.users.iter().any(|&id| user_id == id) {
|
||||
permission_granted = true
|
||||
}
|
||||
// check if the user has an administrating role
|
||||
if !permission_granted
|
||||
&& administrators.roles.iter().any(|role_id| {
|
||||
member.roles.iter().any(|member_role| member_role == role_id)
|
||||
}) {
|
||||
permission_granted = true
|
||||
}
|
||||
|
||||
// if permission is granted, reload the configuration
|
||||
if permission_granted {
|
||||
trace!("{:?} reloading configuration.", command.user);
|
||||
let content = if permission_granted {
|
||||
match command.data.name.as_str() {
|
||||
"reload" => {
|
||||
trace!("{:?} reloaded the configuration.", command.user);
|
||||
|
||||
let new_config = load_configuration();
|
||||
|
||||
@ -83,12 +83,16 @@ impl EventHandler for Handler {
|
||||
configuration.thread_introductions = new_config.thread_introductions;
|
||||
|
||||
"Successfully reloaded configuration.".to_string()
|
||||
} else {
|
||||
// else return an error message
|
||||
"You do not have permission to use this command.".to_string()
|
||||
}
|
||||
},
|
||||
_ => "Unknown command.".to_string(),
|
||||
},
|
||||
"stop" => {
|
||||
trace!("{:?} stopped the bot.", command.user);
|
||||
stop_command = true;
|
||||
"Stopped the bot.".to_string()
|
||||
},
|
||||
_ => "Unknown command.".to_string(),
|
||||
}
|
||||
} else {
|
||||
"You do not have permission to use this command.".to_string()
|
||||
};
|
||||
|
||||
// send the response
|
||||
@ -104,6 +108,10 @@ impl EventHandler for Handler {
|
||||
{
|
||||
error!("Cannot respond to slash command: {}", why);
|
||||
}
|
||||
|
||||
if stop_command {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +121,7 @@ impl EventHandler for Handler {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(response) =
|
||||
if let Some(responder) =
|
||||
get_configuration_lock(&ctx).await.read().await.message_responders.iter().find(
|
||||
|&responder| {
|
||||
// check if the message was sent in a channel that is included in the responder
|
||||
@ -126,7 +134,7 @@ impl EventHandler for Handler {
|
||||
&& contains_match(&responder.includes.match_field, &msg.content)
|
||||
},
|
||||
) {
|
||||
let min_age = response.condition.user.server_age;
|
||||
let min_age = responder.condition.user.server_age;
|
||||
|
||||
if min_age != 0 {
|
||||
let joined_at = ctx
|
||||
@ -146,7 +154,30 @@ impl EventHandler for Handler {
|
||||
return;
|
||||
}
|
||||
|
||||
msg.reply_ping(&ctx.http, &response.message)
|
||||
msg.channel_id
|
||||
.send_message(&ctx.http, |m| {
|
||||
m.reference_message(&msg);
|
||||
match &responder.response.embed {
|
||||
Some(embed) => m.embed(|e| {
|
||||
e.title(&embed.title)
|
||||
.description(&embed.description)
|
||||
.color(embed.color)
|
||||
.fields(embed.fields.iter().map(|field| {
|
||||
(field.name.clone(), field.value.clone(), field.inline)
|
||||
}))
|
||||
.footer(|f| {
|
||||
f.text(&embed.footer.text);
|
||||
f.icon_url(&embed.footer.icon_url)
|
||||
})
|
||||
.thumbnail(&embed.thumbnail.url)
|
||||
.image(&embed.image.url)
|
||||
.author(|a| {
|
||||
a.name(&embed.author.name).icon_url(&embed.author.icon_url)
|
||||
})
|
||||
}),
|
||||
None => m.content(responder.response.message.as_ref().unwrap()),
|
||||
}
|
||||
})
|
||||
.await
|
||||
.expect("Could not reply to message author.");
|
||||
}
|
||||
@ -162,7 +193,9 @@ impl EventHandler for Handler {
|
||||
if let Some(introducer) = &configuration.thread_introductions.iter().find(|introducer| {
|
||||
introducer.channels.iter().any(|channel_id| *channel_id == thread.parent_id.unwrap().0)
|
||||
}) {
|
||||
if let Err(why) = thread.say(&ctx.http, &introducer.message).await {
|
||||
if let Err(why) =
|
||||
thread.say(&ctx.http, &introducer.response.message.as_ref().unwrap()).await
|
||||
{
|
||||
error!("Error sending message: {:?}", why);
|
||||
}
|
||||
}
|
||||
@ -171,11 +204,15 @@ impl EventHandler for Handler {
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
info!("Connected as {}", ready.user.name);
|
||||
|
||||
Command::create_global_application_command(&ctx.http, |command| {
|
||||
command.name("reload").description("Reloads the configuration.")
|
||||
})
|
||||
.await
|
||||
.expect("Could not create command.");
|
||||
for (cmd, description) in
|
||||
[("repload", "Reloads the configuration."), ("stop", "Stop the Discord bot.")]
|
||||
{
|
||||
Command::create_global_application_command(&ctx.http, |command| {
|
||||
command.name(cmd).description(description)
|
||||
})
|
||||
.await
|
||||
.expect("Could not create command.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user